Smart Mentor
A tutoring program using AI to generate questions
Loading...
Searching...
No Matches
ollama.hpp
1/* MIT License
2
3Copyright (c) 2013-2024 Niels Lohmann
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
22*/
23
24// __ _____ _____ _____
25// __| | __| | | | JSON for Modern C++
26// | | |__ | | | | | | version 3.11.3
27// |_____|_____|_____|_|___| https://github.com/nlohmann/json
28//
29// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
30// SPDX-License-Identifier: MIT
31
32/****************************************************************************\
33 * Note on documentation: The source files contain links to the online *
34 * documentation of the public API at https://json.nlohmann.me. This URL *
35 * contains the most recent documentation and should also be applicable to *
36 * previous versions; documentation for deprecated functions is not *
37 * removed, but marked deprecated. See "Generate documentation" section in *
38 * file docs/README.md. *
39\****************************************************************************/
40
41#ifndef INCLUDE_NLOHMANN_JSON_HPP_
42#define INCLUDE_NLOHMANN_JSON_HPP_
43
44#include <algorithm> // all_of, find, for_each
45#include <cstddef> // nullptr_t, ptrdiff_t, size_t
46#include <functional> // hash, less
47#include <initializer_list> // initializer_list
48#ifndef JSON_NO_IO
49 #include <iosfwd> // istream, ostream
50#endif // JSON_NO_IO
51#include <iterator> // random_access_iterator_tag
52#include <memory> // unique_ptr
53#include <string> // string, stoi, to_string
54#include <utility> // declval, forward, move, pair, swap
55#include <vector> // vector
56
57// #include <nlohmann/adl_serializer.hpp>
58// __ _____ _____ _____
59// __| | __| | | | JSON for Modern C++
60// | | |__ | | | | | | version 3.11.3
61// |_____|_____|_____|_|___| https://github.com/nlohmann/json
62//
63// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
64// SPDX-License-Identifier: MIT
65
66
67
68#include <utility>
69
70// #include <nlohmann/detail/abi_macros.hpp>
71// __ _____ _____ _____
72// __| | __| | | | JSON for Modern C++
73// | | |__ | | | | | | version 3.11.3
74// |_____|_____|_____|_|___| https://github.com/nlohmann/json
75//
76// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
77// SPDX-License-Identifier: MIT
78
79
80
81// This file contains all macro definitions affecting or depending on the ABI
82
83#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
84 #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)
85 #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3
86 #warning "Already included a different version of the library!"
87 #endif
88 #endif
89#endif
90
91#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum)
92#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum)
93#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum)
94
95#ifndef JSON_DIAGNOSTICS
96 #define JSON_DIAGNOSTICS 0
97#endif
98
99#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
100 #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
101#endif
102
103#if JSON_DIAGNOSTICS
104 #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag
105#else
106 #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS
107#endif
108
109#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
110 #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp
111#else
112 #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON
113#endif
114
115#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION
116 #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0
117#endif
118
119// Construct the namespace ABI tags component
120#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b
121#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
122 NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
123
124#define NLOHMANN_JSON_ABI_TAGS \
125 NLOHMANN_JSON_ABI_TAGS_CONCAT( \
126 NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
127 NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
128
129// Construct the namespace version component
130#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
131 _v ## major ## _ ## minor ## _ ## patch
132#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
133 NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
134
135#if NLOHMANN_JSON_NAMESPACE_NO_VERSION
136#define NLOHMANN_JSON_NAMESPACE_VERSION
137#else
138#define NLOHMANN_JSON_NAMESPACE_VERSION \
139 NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
140 NLOHMANN_JSON_VERSION_MINOR, \
141 NLOHMANN_JSON_VERSION_PATCH)
142#endif
143
144// Combine namespace components
145#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b
146#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
147 NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
148
149#ifndef NLOHMANN_JSON_NAMESPACE
150#define NLOHMANN_JSON_NAMESPACE \
151 nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
152 NLOHMANN_JSON_ABI_TAGS, \
153 NLOHMANN_JSON_NAMESPACE_VERSION)
154#endif
155
156#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
157#define NLOHMANN_JSON_NAMESPACE_BEGIN \
158 namespace nlohmann \
159 { \
160 inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
161 NLOHMANN_JSON_ABI_TAGS, \
162 NLOHMANN_JSON_NAMESPACE_VERSION) \
163 {
164#endif
165
166#ifndef NLOHMANN_JSON_NAMESPACE_END
167#define NLOHMANN_JSON_NAMESPACE_END \
168 } /* namespace (inline namespace) NOLINT(readability/namespace) */ \
169 } // namespace nlohmann
170#endif
171
172// #include <nlohmann/detail/conversions/from_json.hpp>
173// __ _____ _____ _____
174// __| | __| | | | JSON for Modern C++
175// | | |__ | | | | | | version 3.11.3
176// |_____|_____|_____|_|___| https://github.com/nlohmann/json
177//
178// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
179// SPDX-License-Identifier: MIT
180
181
182
183#include <algorithm> // transform
184#include <array> // array
185#include <forward_list> // forward_list
186#include <iterator> // inserter, front_inserter, end
187#include <map> // map
188#include <string> // string
189#include <tuple> // tuple, make_tuple
190#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
191#include <unordered_map> // unordered_map
192#include <utility> // pair, declval
193#include <valarray> // valarray
194
195// #include <nlohmann/detail/exceptions.hpp>
196// __ _____ _____ _____
197// __| | __| | | | JSON for Modern C++
198// | | |__ | | | | | | version 3.11.3
199// |_____|_____|_____|_|___| https://github.com/nlohmann/json
200//
201// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
202// SPDX-License-Identifier: MIT
203
204
205
206#include <cstddef> // nullptr_t
207#include <exception> // exception
208#if JSON_DIAGNOSTICS
209 #include <numeric> // accumulate
210#endif
211#include <stdexcept> // runtime_error
212#include <string> // to_string
213#include <vector> // vector
214
215// #include <nlohmann/detail/value_t.hpp>
216// __ _____ _____ _____
217// __| | __| | | | JSON for Modern C++
218// | | |__ | | | | | | version 3.11.3
219// |_____|_____|_____|_|___| https://github.com/nlohmann/json
220//
221// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
222// SPDX-License-Identifier: MIT
223
224
225
226#include <array> // array
227#include <cstddef> // size_t
228#include <cstdint> // uint8_t
229#include <string> // string
230
231// #include <nlohmann/detail/macro_scope.hpp>
232// __ _____ _____ _____
233// __| | __| | | | JSON for Modern C++
234// | | |__ | | | | | | version 3.11.3
235// |_____|_____|_____|_|___| https://github.com/nlohmann/json
236//
237// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
238// SPDX-License-Identifier: MIT
239
240
241
242#include <utility> // declval, pair
243// #include <nlohmann/detail/meta/detected.hpp>
244// __ _____ _____ _____
245// __| | __| | | | JSON for Modern C++
246// | | |__ | | | | | | version 3.11.3
247// |_____|_____|_____|_|___| https://github.com/nlohmann/json
248//
249// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
250// SPDX-License-Identifier: MIT
251
252
253
254#include <type_traits>
255
256// #include <nlohmann/detail/meta/void_t.hpp>
257// __ _____ _____ _____
258// __| | __| | | | JSON for Modern C++
259// | | |__ | | | | | | version 3.11.3
260// |_____|_____|_____|_|___| https://github.com/nlohmann/json
261//
262// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
263// SPDX-License-Identifier: MIT
264
265
266
267// #include <nlohmann/detail/abi_macros.hpp>
268
269
270NLOHMANN_JSON_NAMESPACE_BEGIN
271namespace detail
272{
273
274template<typename ...Ts> struct make_void
275{
276 using type = void;
277};
278template<typename ...Ts> using void_t = typename make_void<Ts...>::type;
279
280} // namespace detail
281NLOHMANN_JSON_NAMESPACE_END
282
283
284NLOHMANN_JSON_NAMESPACE_BEGIN
285namespace detail
286{
287
288// https://en.cppreference.com/w/cpp/experimental/is_detected
290{
291 nonesuch() = delete;
292 ~nonesuch() = delete;
293 nonesuch(nonesuch const&) = delete;
294 nonesuch(nonesuch const&&) = delete;
295 void operator=(nonesuch const&) = delete;
296 void operator=(nonesuch&&) = delete;
297};
298
299template<class Default,
300 class AlwaysVoid,
301 template<class...> class Op,
302 class... Args>
304{
305 using value_t = std::false_type;
306 using type = Default;
307};
308
309template<class Default, template<class...> class Op, class... Args>
310struct detector<Default, void_t<Op<Args...>>, Op, Args...>
311{
312 using value_t = std::true_type;
313 using type = Op<Args...>;
314};
315
316template<template<class...> class Op, class... Args>
317using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
318
319template<template<class...> class Op, class... Args>
320struct is_detected_lazy : is_detected<Op, Args...> { };
321
322template<template<class...> class Op, class... Args>
323using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
324
325template<class Default, template<class...> class Op, class... Args>
326using detected_or = detector<Default, void, Op, Args...>;
327
328template<class Default, template<class...> class Op, class... Args>
329using detected_or_t = typename detected_or<Default, Op, Args...>::type;
330
331template<class Expected, template<class...> class Op, class... Args>
332using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
333
334template<class To, template<class...> class Op, class... Args>
335using is_detected_convertible =
336 std::is_convertible<detected_t<Op, Args...>, To>;
337
338} // namespace detail
339NLOHMANN_JSON_NAMESPACE_END
340
341// #include <nlohmann/thirdparty/hedley/hedley.hpp>
342
343
344// __ _____ _____ _____
345// __| | __| | | | JSON for Modern C++
346// | | |__ | | | | | | version 3.11.3
347// |_____|_____|_____|_|___| https://github.com/nlohmann/json
348//
349// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
350// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson <evan@nemerson.com>
351// SPDX-License-Identifier: MIT
352
353/* Hedley - https://nemequ.github.io/hedley
354 * Created by Evan Nemerson <evan@nemerson.com>
355 */
356
357#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15)
358#if defined(JSON_HEDLEY_VERSION)
359 #undef JSON_HEDLEY_VERSION
360#endif
361#define JSON_HEDLEY_VERSION 15
362
363#if defined(JSON_HEDLEY_STRINGIFY_EX)
364 #undef JSON_HEDLEY_STRINGIFY_EX
365#endif
366#define JSON_HEDLEY_STRINGIFY_EX(x) #x
367
368#if defined(JSON_HEDLEY_STRINGIFY)
369 #undef JSON_HEDLEY_STRINGIFY
370#endif
371#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x)
372
373#if defined(JSON_HEDLEY_CONCAT_EX)
374 #undef JSON_HEDLEY_CONCAT_EX
375#endif
376#define JSON_HEDLEY_CONCAT_EX(a,b) a##b
377
378#if defined(JSON_HEDLEY_CONCAT)
379 #undef JSON_HEDLEY_CONCAT
380#endif
381#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b)
382
383#if defined(JSON_HEDLEY_CONCAT3_EX)
384 #undef JSON_HEDLEY_CONCAT3_EX
385#endif
386#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c
387
388#if defined(JSON_HEDLEY_CONCAT3)
389 #undef JSON_HEDLEY_CONCAT3
390#endif
391#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c)
392
393#if defined(JSON_HEDLEY_VERSION_ENCODE)
394 #undef JSON_HEDLEY_VERSION_ENCODE
395#endif
396#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision))
397
398#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR)
399 #undef JSON_HEDLEY_VERSION_DECODE_MAJOR
400#endif
401#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000)
402
403#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR)
404 #undef JSON_HEDLEY_VERSION_DECODE_MINOR
405#endif
406#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000)
407
408#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION)
409 #undef JSON_HEDLEY_VERSION_DECODE_REVISION
410#endif
411#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000)
412
413#if defined(JSON_HEDLEY_GNUC_VERSION)
414 #undef JSON_HEDLEY_GNUC_VERSION
415#endif
416#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)
417 #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
418#elif defined(__GNUC__)
419 #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0)
420#endif
421
422#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK)
423 #undef JSON_HEDLEY_GNUC_VERSION_CHECK
424#endif
425#if defined(JSON_HEDLEY_GNUC_VERSION)
426 #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
427#else
428 #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0)
429#endif
430
431#if defined(JSON_HEDLEY_MSVC_VERSION)
432 #undef JSON_HEDLEY_MSVC_VERSION
433#endif
434#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL)
435 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)
436#elif defined(_MSC_FULL_VER) && !defined(__ICL)
437 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)
438#elif defined(_MSC_VER) && !defined(__ICL)
439 #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)
440#endif
441
442#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK)
443 #undef JSON_HEDLEY_MSVC_VERSION_CHECK
444#endif
445#if !defined(JSON_HEDLEY_MSVC_VERSION)
446 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0)
447#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
448 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))
449#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
450 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))
451#else
452 #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor)))
453#endif
454
455#if defined(JSON_HEDLEY_INTEL_VERSION)
456 #undef JSON_HEDLEY_INTEL_VERSION
457#endif
458#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL)
459 #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)
460#elif defined(__INTEL_COMPILER) && !defined(__ICL)
461 #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)
462#endif
463
464#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK)
465 #undef JSON_HEDLEY_INTEL_VERSION_CHECK
466#endif
467#if defined(JSON_HEDLEY_INTEL_VERSION)
468 #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
469#else
470 #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0)
471#endif
472
473#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
474 #undef JSON_HEDLEY_INTEL_CL_VERSION
475#endif
476#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL)
477 #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0)
478#endif
479
480#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK)
481 #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
482#endif
483#if defined(JSON_HEDLEY_INTEL_CL_VERSION)
484 #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
485#else
486 #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0)
487#endif
488
489#if defined(JSON_HEDLEY_PGI_VERSION)
490 #undef JSON_HEDLEY_PGI_VERSION
491#endif
492#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)
493 #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)
494#endif
495
496#if defined(JSON_HEDLEY_PGI_VERSION_CHECK)
497 #undef JSON_HEDLEY_PGI_VERSION_CHECK
498#endif
499#if defined(JSON_HEDLEY_PGI_VERSION)
500 #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
501#else
502 #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0)
503#endif
504
505#if defined(JSON_HEDLEY_SUNPRO_VERSION)
506 #undef JSON_HEDLEY_SUNPRO_VERSION
507#endif
508#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
509 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10)
510#elif defined(__SUNPRO_C)
511 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf)
512#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
513 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10)
514#elif defined(__SUNPRO_CC)
515 #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf)
516#endif
517
518#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK)
519 #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
520#endif
521#if defined(JSON_HEDLEY_SUNPRO_VERSION)
522 #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
523#else
524 #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0)
525#endif
526
527#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
528 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION
529#endif
530#if defined(__EMSCRIPTEN__)
531 #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__)
532#endif
533
534#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK)
535 #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
536#endif
537#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)
538 #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
539#else
540 #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0)
541#endif
542
543#if defined(JSON_HEDLEY_ARM_VERSION)
544 #undef JSON_HEDLEY_ARM_VERSION
545#endif
546#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)
547 #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100)
548#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)
549 #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100)
550#endif
551
552#if defined(JSON_HEDLEY_ARM_VERSION_CHECK)
553 #undef JSON_HEDLEY_ARM_VERSION_CHECK
554#endif
555#if defined(JSON_HEDLEY_ARM_VERSION)
556 #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
557#else
558 #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0)
559#endif
560
561#if defined(JSON_HEDLEY_IBM_VERSION)
562 #undef JSON_HEDLEY_IBM_VERSION
563#endif
564#if defined(__ibmxl__)
565 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__)
566#elif defined(__xlC__) && defined(__xlC_ver__)
567 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)
568#elif defined(__xlC__)
569 #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0)
570#endif
571
572#if defined(JSON_HEDLEY_IBM_VERSION_CHECK)
573 #undef JSON_HEDLEY_IBM_VERSION_CHECK
574#endif
575#if defined(JSON_HEDLEY_IBM_VERSION)
576 #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
577#else
578 #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0)
579#endif
580
581#if defined(JSON_HEDLEY_TI_VERSION)
582 #undef JSON_HEDLEY_TI_VERSION
583#endif
584#if \
585 defined(__TI_COMPILER_VERSION__) && \
586 ( \
587 defined(__TMS470__) || defined(__TI_ARM__) || \
588 defined(__MSP430__) || \
589 defined(__TMS320C2000__) \
590 )
591#if (__TI_COMPILER_VERSION__ >= 16000000)
592 #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
593#endif
594#endif
595
596#if defined(JSON_HEDLEY_TI_VERSION_CHECK)
597 #undef JSON_HEDLEY_TI_VERSION_CHECK
598#endif
599#if defined(JSON_HEDLEY_TI_VERSION)
600 #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
601#else
602 #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0)
603#endif
604
605#if defined(JSON_HEDLEY_TI_CL2000_VERSION)
606 #undef JSON_HEDLEY_TI_CL2000_VERSION
607#endif
608#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__)
609 #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
610#endif
611
612#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK)
613 #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK
614#endif
615#if defined(JSON_HEDLEY_TI_CL2000_VERSION)
616 #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
617#else
618 #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0)
619#endif
620
621#if defined(JSON_HEDLEY_TI_CL430_VERSION)
622 #undef JSON_HEDLEY_TI_CL430_VERSION
623#endif
624#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__)
625 #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
626#endif
627
628#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK)
629 #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK
630#endif
631#if defined(JSON_HEDLEY_TI_CL430_VERSION)
632 #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
633#else
634 #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0)
635#endif
636
637#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)
638 #undef JSON_HEDLEY_TI_ARMCL_VERSION
639#endif
640#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__))
641 #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
642#endif
643
644#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK)
645 #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK
646#endif
647#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)
648 #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
649#else
650 #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0)
651#endif
652
653#if defined(JSON_HEDLEY_TI_CL6X_VERSION)
654 #undef JSON_HEDLEY_TI_CL6X_VERSION
655#endif
656#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__)
657 #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
658#endif
659
660#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK)
661 #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK
662#endif
663#if defined(JSON_HEDLEY_TI_CL6X_VERSION)
664 #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
665#else
666 #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0)
667#endif
668
669#if defined(JSON_HEDLEY_TI_CL7X_VERSION)
670 #undef JSON_HEDLEY_TI_CL7X_VERSION
671#endif
672#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__)
673 #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
674#endif
675
676#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK)
677 #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK
678#endif
679#if defined(JSON_HEDLEY_TI_CL7X_VERSION)
680 #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
681#else
682 #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0)
683#endif
684
685#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)
686 #undef JSON_HEDLEY_TI_CLPRU_VERSION
687#endif
688#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__)
689 #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))
690#endif
691
692#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK)
693 #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK
694#endif
695#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)
696 #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
697#else
698 #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0)
699#endif
700
701#if defined(JSON_HEDLEY_CRAY_VERSION)
702 #undef JSON_HEDLEY_CRAY_VERSION
703#endif
704#if defined(_CRAYC)
705 #if defined(_RELEASE_PATCHLEVEL)
706 #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL)
707 #else
708 #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0)
709 #endif
710#endif
711
712#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK)
713 #undef JSON_HEDLEY_CRAY_VERSION_CHECK
714#endif
715#if defined(JSON_HEDLEY_CRAY_VERSION)
716 #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
717#else
718 #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0)
719#endif
720
721#if defined(JSON_HEDLEY_IAR_VERSION)
722 #undef JSON_HEDLEY_IAR_VERSION
723#endif
724#if defined(__IAR_SYSTEMS_ICC__)
725 #if __VER__ > 1000
726 #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000))
727 #else
728 #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0)
729 #endif
730#endif
731
732#if defined(JSON_HEDLEY_IAR_VERSION_CHECK)
733 #undef JSON_HEDLEY_IAR_VERSION_CHECK
734#endif
735#if defined(JSON_HEDLEY_IAR_VERSION)
736 #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
737#else
738 #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0)
739#endif
740
741#if defined(JSON_HEDLEY_TINYC_VERSION)
742 #undef JSON_HEDLEY_TINYC_VERSION
743#endif
744#if defined(__TINYC__)
745 #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)
746#endif
747
748#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK)
749 #undef JSON_HEDLEY_TINYC_VERSION_CHECK
750#endif
751#if defined(JSON_HEDLEY_TINYC_VERSION)
752 #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
753#else
754 #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0)
755#endif
756
757#if defined(JSON_HEDLEY_DMC_VERSION)
758 #undef JSON_HEDLEY_DMC_VERSION
759#endif
760#if defined(__DMC__)
761 #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf)
762#endif
763
764#if defined(JSON_HEDLEY_DMC_VERSION_CHECK)
765 #undef JSON_HEDLEY_DMC_VERSION_CHECK
766#endif
767#if defined(JSON_HEDLEY_DMC_VERSION)
768 #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
769#else
770 #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0)
771#endif
772
773#if defined(JSON_HEDLEY_COMPCERT_VERSION)
774 #undef JSON_HEDLEY_COMPCERT_VERSION
775#endif
776#if defined(__COMPCERT_VERSION__)
777 #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100)
778#endif
779
780#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK)
781 #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
782#endif
783#if defined(JSON_HEDLEY_COMPCERT_VERSION)
784 #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
785#else
786 #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0)
787#endif
788
789#if defined(JSON_HEDLEY_PELLES_VERSION)
790 #undef JSON_HEDLEY_PELLES_VERSION
791#endif
792#if defined(__POCC__)
793 #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0)
794#endif
795
796#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK)
797 #undef JSON_HEDLEY_PELLES_VERSION_CHECK
798#endif
799#if defined(JSON_HEDLEY_PELLES_VERSION)
800 #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
801#else
802 #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0)
803#endif
804
805#if defined(JSON_HEDLEY_MCST_LCC_VERSION)
806 #undef JSON_HEDLEY_MCST_LCC_VERSION
807#endif
808#if defined(__LCC__) && defined(__LCC_MINOR__)
809 #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__)
810#endif
811
812#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK)
813 #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK
814#endif
815#if defined(JSON_HEDLEY_MCST_LCC_VERSION)
816 #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
817#else
818 #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0)
819#endif
820
821#if defined(JSON_HEDLEY_GCC_VERSION)
822 #undef JSON_HEDLEY_GCC_VERSION
823#endif
824#if \
825 defined(JSON_HEDLEY_GNUC_VERSION) && \
826 !defined(__clang__) && \
827 !defined(JSON_HEDLEY_INTEL_VERSION) && \
828 !defined(JSON_HEDLEY_PGI_VERSION) && \
829 !defined(JSON_HEDLEY_ARM_VERSION) && \
830 !defined(JSON_HEDLEY_CRAY_VERSION) && \
831 !defined(JSON_HEDLEY_TI_VERSION) && \
832 !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \
833 !defined(JSON_HEDLEY_TI_CL430_VERSION) && \
834 !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \
835 !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \
836 !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \
837 !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \
838 !defined(__COMPCERT__) && \
839 !defined(JSON_HEDLEY_MCST_LCC_VERSION)
840 #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION
841#endif
842
843#if defined(JSON_HEDLEY_GCC_VERSION_CHECK)
844 #undef JSON_HEDLEY_GCC_VERSION_CHECK
845#endif
846#if defined(JSON_HEDLEY_GCC_VERSION)
847 #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))
848#else
849 #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0)
850#endif
851
852#if defined(JSON_HEDLEY_HAS_ATTRIBUTE)
853 #undef JSON_HEDLEY_HAS_ATTRIBUTE
854#endif
855#if \
856 defined(__has_attribute) && \
857 ( \
858 (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \
859 )
860# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute)
861#else
862# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0)
863#endif
864
865#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE)
866 #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
867#endif
868#if defined(__has_attribute)
869 #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
870#else
871 #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
872#endif
873
874#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE)
875 #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
876#endif
877#if defined(__has_attribute)
878 #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
879#else
880 #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
881#endif
882
883#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE)
884 #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
885#endif
886#if \
887 defined(__has_cpp_attribute) && \
888 defined(__cplusplus) && \
889 (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0))
890 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute)
891#else
892 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0)
893#endif
894
895#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS)
896 #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS
897#endif
898#if !defined(__cplusplus) || !defined(__has_cpp_attribute)
899 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
900#elif \
901 !defined(JSON_HEDLEY_PGI_VERSION) && \
902 !defined(JSON_HEDLEY_IAR_VERSION) && \
903 (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \
904 (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0))
905 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute)
906#else
907 #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)
908#endif
909
910#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE)
911 #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
912#endif
913#if defined(__has_cpp_attribute) && defined(__cplusplus)
914 #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
915#else
916 #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
917#endif
918
919#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE)
920 #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
921#endif
922#if defined(__has_cpp_attribute) && defined(__cplusplus)
923 #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)
924#else
925 #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
926#endif
927
928#if defined(JSON_HEDLEY_HAS_BUILTIN)
929 #undef JSON_HEDLEY_HAS_BUILTIN
930#endif
931#if defined(__has_builtin)
932 #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin)
933#else
934 #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0)
935#endif
936
937#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN)
938 #undef JSON_HEDLEY_GNUC_HAS_BUILTIN
939#endif
940#if defined(__has_builtin)
941 #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
942#else
943 #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
944#endif
945
946#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN)
947 #undef JSON_HEDLEY_GCC_HAS_BUILTIN
948#endif
949#if defined(__has_builtin)
950 #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)
951#else
952 #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
953#endif
954
955#if defined(JSON_HEDLEY_HAS_FEATURE)
956 #undef JSON_HEDLEY_HAS_FEATURE
957#endif
958#if defined(__has_feature)
959 #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature)
960#else
961 #define JSON_HEDLEY_HAS_FEATURE(feature) (0)
962#endif
963
964#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE)
965 #undef JSON_HEDLEY_GNUC_HAS_FEATURE
966#endif
967#if defined(__has_feature)
968 #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
969#else
970 #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
971#endif
972
973#if defined(JSON_HEDLEY_GCC_HAS_FEATURE)
974 #undef JSON_HEDLEY_GCC_HAS_FEATURE
975#endif
976#if defined(__has_feature)
977 #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)
978#else
979 #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
980#endif
981
982#if defined(JSON_HEDLEY_HAS_EXTENSION)
983 #undef JSON_HEDLEY_HAS_EXTENSION
984#endif
985#if defined(__has_extension)
986 #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension)
987#else
988 #define JSON_HEDLEY_HAS_EXTENSION(extension) (0)
989#endif
990
991#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION)
992 #undef JSON_HEDLEY_GNUC_HAS_EXTENSION
993#endif
994#if defined(__has_extension)
995 #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
996#else
997 #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
998#endif
999
1000#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION)
1001 #undef JSON_HEDLEY_GCC_HAS_EXTENSION
1002#endif
1003#if defined(__has_extension)
1004 #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)
1005#else
1006 #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
1007#endif
1008
1009#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE)
1010 #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
1011#endif
1012#if defined(__has_declspec_attribute)
1013 #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute)
1014#else
1015 #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0)
1016#endif
1017
1018#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE)
1019 #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
1020#endif
1021#if defined(__has_declspec_attribute)
1022 #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
1023#else
1024 #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
1025#endif
1026
1027#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE)
1028 #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
1029#endif
1030#if defined(__has_declspec_attribute)
1031 #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)
1032#else
1033 #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
1034#endif
1035
1036#if defined(JSON_HEDLEY_HAS_WARNING)
1037 #undef JSON_HEDLEY_HAS_WARNING
1038#endif
1039#if defined(__has_warning)
1040 #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning)
1041#else
1042 #define JSON_HEDLEY_HAS_WARNING(warning) (0)
1043#endif
1044
1045#if defined(JSON_HEDLEY_GNUC_HAS_WARNING)
1046 #undef JSON_HEDLEY_GNUC_HAS_WARNING
1047#endif
1048#if defined(__has_warning)
1049 #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
1050#else
1051 #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)
1052#endif
1053
1054#if defined(JSON_HEDLEY_GCC_HAS_WARNING)
1055 #undef JSON_HEDLEY_GCC_HAS_WARNING
1056#endif
1057#if defined(__has_warning)
1058 #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)
1059#else
1060 #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
1061#endif
1062
1063#if \
1064 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
1065 defined(__clang__) || \
1066 JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
1067 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1068 JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
1069 JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
1070 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1071 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1072 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
1073 JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
1074 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
1075 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \
1076 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1077 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1078 JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \
1079 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \
1080 JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \
1081 (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))
1082 #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value)
1083#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
1084 #define JSON_HEDLEY_PRAGMA(value) __pragma(value)
1085#else
1086 #define JSON_HEDLEY_PRAGMA(value)
1087#endif
1088
1089#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH)
1090 #undef JSON_HEDLEY_DIAGNOSTIC_PUSH
1091#endif
1092#if defined(JSON_HEDLEY_DIAGNOSTIC_POP)
1093 #undef JSON_HEDLEY_DIAGNOSTIC_POP
1094#endif
1095#if defined(__clang__)
1096 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push")
1097 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop")
1098#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
1099 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
1100 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
1101#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
1102 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
1103 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
1104#elif \
1105 JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
1106 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1107 #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))
1108 #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))
1109#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0)
1110 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push")
1111 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop")
1112#elif \
1113 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1114 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1115 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \
1116 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
1117 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1118 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
1119 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push")
1120 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop")
1121#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
1122 #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)")
1123 #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)")
1124#else
1125 #define JSON_HEDLEY_DIAGNOSTIC_PUSH
1126 #define JSON_HEDLEY_DIAGNOSTIC_POP
1127#endif
1128
1129/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for
1130 HEDLEY INTERNAL USE ONLY. API subject to change without notice. */
1131#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
1132 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
1133#endif
1134#if defined(__cplusplus)
1135# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat")
1136# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions")
1137# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions")
1138# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
1139 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1140 _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
1141 _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
1142 _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \
1143 xpr \
1144 JSON_HEDLEY_DIAGNOSTIC_POP
1145# else
1146# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
1147 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1148 _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
1149 _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \
1150 xpr \
1151 JSON_HEDLEY_DIAGNOSTIC_POP
1152# endif
1153# else
1154# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \
1155 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1156 _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \
1157 xpr \
1158 JSON_HEDLEY_DIAGNOSTIC_POP
1159# endif
1160# endif
1161#endif
1162#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)
1163 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x
1164#endif
1165
1166#if defined(JSON_HEDLEY_CONST_CAST)
1167 #undef JSON_HEDLEY_CONST_CAST
1168#endif
1169#if defined(__cplusplus)
1170# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast<T>(expr))
1171#elif \
1172 JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \
1173 JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \
1174 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
1175# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \
1176 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1177 JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \
1178 ((T) (expr)); \
1179 JSON_HEDLEY_DIAGNOSTIC_POP \
1180 }))
1181#else
1182# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr))
1183#endif
1184
1185#if defined(JSON_HEDLEY_REINTERPRET_CAST)
1186 #undef JSON_HEDLEY_REINTERPRET_CAST
1187#endif
1188#if defined(__cplusplus)
1189 #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr))
1190#else
1191 #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr))
1192#endif
1193
1194#if defined(JSON_HEDLEY_STATIC_CAST)
1195 #undef JSON_HEDLEY_STATIC_CAST
1196#endif
1197#if defined(__cplusplus)
1198 #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast<T>(expr))
1199#else
1200 #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr))
1201#endif
1202
1203#if defined(JSON_HEDLEY_CPP_CAST)
1204 #undef JSON_HEDLEY_CPP_CAST
1205#endif
1206#if defined(__cplusplus)
1207# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast")
1208# define JSON_HEDLEY_CPP_CAST(T, expr) \
1209 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1210 _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \
1211 ((T) (expr)) \
1212 JSON_HEDLEY_DIAGNOSTIC_POP
1213# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0)
1214# define JSON_HEDLEY_CPP_CAST(T, expr) \
1215 JSON_HEDLEY_DIAGNOSTIC_PUSH \
1216 _Pragma("diag_suppress=Pe137") \
1217 JSON_HEDLEY_DIAGNOSTIC_POP
1218# else
1219# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr))
1220# endif
1221#else
1222# define JSON_HEDLEY_CPP_CAST(T, expr) (expr)
1223#endif
1224
1225#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED)
1226 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
1227#endif
1228#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations")
1229 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
1230#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
1231 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)")
1232#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1233 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786))
1234#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
1235 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445")
1236#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
1237 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
1238#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
1239 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
1240#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
1241 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996))
1242#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1243 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444")
1244#elif \
1245 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1246 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1247 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1248 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1249 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1250 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1251 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1252 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1253 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1254 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1255 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)
1256 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718")
1257#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus)
1258 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)")
1259#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus)
1260 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)")
1261#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1262 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215")
1263#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)
1264 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)")
1265#else
1266 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
1267#endif
1268
1269#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS)
1270 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
1271#endif
1272#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
1273 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"")
1274#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
1275 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)")
1276#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1277 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161))
1278#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
1279 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675")
1280#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)
1281 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"")
1282#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)
1283 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068))
1284#elif \
1285 JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \
1286 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \
1287 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1288 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0)
1289 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
1290#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0)
1291 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163")
1292#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1293 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161")
1294#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1295 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161")
1296#else
1297 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
1298#endif
1299
1300#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES)
1301 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
1302#endif
1303#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes")
1304 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"")
1305#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)
1306 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
1307#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0)
1308 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)")
1309#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1310 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292))
1311#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0)
1312 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030))
1313#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)
1314 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098")
1315#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)
1316 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
1317#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)
1318 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)")
1319#elif \
1320 JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \
1321 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \
1322 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0)
1323 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173")
1324#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1325 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097")
1326#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1327 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097")
1328#else
1329 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
1330#endif
1331
1332#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL)
1333 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
1334#endif
1335#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual")
1336 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"")
1337#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
1338 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)")
1339#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0)
1340 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
1341#else
1342 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
1343#endif
1344
1345#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION)
1346 #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
1347#endif
1348#if JSON_HEDLEY_HAS_WARNING("-Wunused-function")
1349 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"")
1350#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0)
1351 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"")
1352#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0)
1353 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505))
1354#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1355 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142")
1356#else
1357 #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
1358#endif
1359
1360#if defined(JSON_HEDLEY_DEPRECATED)
1361 #undef JSON_HEDLEY_DEPRECATED
1362#endif
1363#if defined(JSON_HEDLEY_DEPRECATED_FOR)
1364 #undef JSON_HEDLEY_DEPRECATED_FOR
1365#endif
1366#if \
1367 JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
1368 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1369 #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since))
1370 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement))
1371#elif \
1372 (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \
1373 JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
1374 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1375 JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
1376 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \
1377 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
1378 JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \
1379 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \
1380 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \
1381 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1382 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \
1383 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1384 #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since)))
1385 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement)))
1386#elif defined(__cplusplus) && (__cplusplus >= 201402L)
1387 #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]])
1388 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]])
1389#elif \
1390 JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \
1391 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
1392 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1393 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1394 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1395 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1396 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1397 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1398 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1399 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1400 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1401 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1402 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1403 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1404 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
1405 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
1406 #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))
1407 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))
1408#elif \
1409 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
1410 JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \
1411 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1412 #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated)
1413 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)
1414#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1415 #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated")
1416 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated")
1417#else
1418 #define JSON_HEDLEY_DEPRECATED(since)
1419 #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement)
1420#endif
1421
1422#if defined(JSON_HEDLEY_UNAVAILABLE)
1423 #undef JSON_HEDLEY_UNAVAILABLE
1424#endif
1425#if \
1426 JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \
1427 JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \
1428 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1429 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1430 #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since)))
1431#else
1432 #define JSON_HEDLEY_UNAVAILABLE(available_since)
1433#endif
1434
1435#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT)
1436 #undef JSON_HEDLEY_WARN_UNUSED_RESULT
1437#endif
1438#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG)
1439 #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG
1440#endif
1441#if \
1442 JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \
1443 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
1444 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1445 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1446 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1447 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1448 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1449 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1450 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1451 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1452 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1453 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1454 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1455 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1456 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
1457 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
1458 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1459 #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
1460 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__))
1461#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L)
1462 #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
1463 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]])
1464#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard)
1465 #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
1466 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])
1467#elif defined(_Check_return_) /* SAL */
1468 #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_
1469 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_
1470#else
1471 #define JSON_HEDLEY_WARN_UNUSED_RESULT
1472 #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg)
1473#endif
1474
1475#if defined(JSON_HEDLEY_SENTINEL)
1476 #undef JSON_HEDLEY_SENTINEL
1477#endif
1478#if \
1479 JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \
1480 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
1481 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1482 JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \
1483 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1484 #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position)))
1485#else
1486 #define JSON_HEDLEY_SENTINEL(position)
1487#endif
1488
1489#if defined(JSON_HEDLEY_NO_RETURN)
1490 #undef JSON_HEDLEY_NO_RETURN
1491#endif
1492#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1493 #define JSON_HEDLEY_NO_RETURN __noreturn
1494#elif \
1495 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1496 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1497 #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
1498#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
1499 #define JSON_HEDLEY_NO_RETURN _Noreturn
1500#elif defined(__cplusplus) && (__cplusplus >= 201103L)
1501 #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]])
1502#elif \
1503 JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \
1504 JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \
1505 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
1506 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1507 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1508 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1509 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1510 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1511 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1512 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1513 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1514 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1515 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1516 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1517 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1518 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1519 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
1520 #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))
1521#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
1522 #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return")
1523#elif \
1524 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
1525 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1526 #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
1527#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
1528 #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;")
1529#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
1530 #define JSON_HEDLEY_NO_RETURN __attribute((noreturn))
1531#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
1532 #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)
1533#else
1534 #define JSON_HEDLEY_NO_RETURN
1535#endif
1536
1537#if defined(JSON_HEDLEY_NO_ESCAPE)
1538 #undef JSON_HEDLEY_NO_ESCAPE
1539#endif
1540#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape)
1541 #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__))
1542#else
1543 #define JSON_HEDLEY_NO_ESCAPE
1544#endif
1545
1546#if defined(JSON_HEDLEY_UNREACHABLE)
1547 #undef JSON_HEDLEY_UNREACHABLE
1548#endif
1549#if defined(JSON_HEDLEY_UNREACHABLE_RETURN)
1550 #undef JSON_HEDLEY_UNREACHABLE_RETURN
1551#endif
1552#if defined(JSON_HEDLEY_ASSUME)
1553 #undef JSON_HEDLEY_ASSUME
1554#endif
1555#if \
1556 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
1557 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1558 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1559 #define JSON_HEDLEY_ASSUME(expr) __assume(expr)
1560#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume)
1561 #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr)
1562#elif \
1563 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
1564 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)
1565 #if defined(__cplusplus)
1566 #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr)
1567 #else
1568 #define JSON_HEDLEY_ASSUME(expr) _nassert(expr)
1569 #endif
1570#endif
1571#if \
1572 (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \
1573 JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \
1574 JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \
1575 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1576 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \
1577 JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \
1578 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1579 #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable()
1580#elif defined(JSON_HEDLEY_ASSUME)
1581 #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)
1582#endif
1583#if !defined(JSON_HEDLEY_ASSUME)
1584 #if defined(JSON_HEDLEY_UNREACHABLE)
1585 #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1)))
1586 #else
1587 #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr)
1588 #endif
1589#endif
1590#if defined(JSON_HEDLEY_UNREACHABLE)
1591 #if \
1592 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
1593 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)
1594 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value))
1595 #else
1596 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE()
1597 #endif
1598#else
1599 #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value)
1600#endif
1601#if !defined(JSON_HEDLEY_UNREACHABLE)
1602 #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)
1603#endif
1604
1605JSON_HEDLEY_DIAGNOSTIC_PUSH
1606#if JSON_HEDLEY_HAS_WARNING("-Wpedantic")
1607 #pragma clang diagnostic ignored "-Wpedantic"
1608#endif
1609#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus)
1610 #pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
1611#endif
1612#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0)
1613 #if defined(__clang__)
1614 #pragma clang diagnostic ignored "-Wvariadic-macros"
1615 #elif defined(JSON_HEDLEY_GCC_VERSION)
1616 #pragma GCC diagnostic ignored "-Wvariadic-macros"
1617 #endif
1618#endif
1619#if defined(JSON_HEDLEY_NON_NULL)
1620 #undef JSON_HEDLEY_NON_NULL
1621#endif
1622#if \
1623 JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \
1624 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
1625 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1626 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
1627 #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))
1628#else
1629 #define JSON_HEDLEY_NON_NULL(...)
1630#endif
1631JSON_HEDLEY_DIAGNOSTIC_POP
1632
1633#if defined(JSON_HEDLEY_PRINTF_FORMAT)
1634 #undef JSON_HEDLEY_PRINTF_FORMAT
1635#endif
1636#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO)
1637 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check)))
1638#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO)
1639 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check)))
1640#elif \
1641 JSON_HEDLEY_HAS_ATTRIBUTE(format) || \
1642 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
1643 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1644 JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \
1645 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1646 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1647 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1648 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1649 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1650 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1651 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1652 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1653 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1654 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1655 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1656 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1657 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1658 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check)))
1659#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0)
1660 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check))
1661#else
1662 #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check)
1663#endif
1664
1665#if defined(JSON_HEDLEY_CONSTEXPR)
1666 #undef JSON_HEDLEY_CONSTEXPR
1667#endif
1668#if defined(__cplusplus)
1669 #if __cplusplus >= 201103L
1670 #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr)
1671 #endif
1672#endif
1673#if !defined(JSON_HEDLEY_CONSTEXPR)
1674 #define JSON_HEDLEY_CONSTEXPR
1675#endif
1676
1677#if defined(JSON_HEDLEY_PREDICT)
1678 #undef JSON_HEDLEY_PREDICT
1679#endif
1680#if defined(JSON_HEDLEY_LIKELY)
1681 #undef JSON_HEDLEY_LIKELY
1682#endif
1683#if defined(JSON_HEDLEY_UNLIKELY)
1684 #undef JSON_HEDLEY_UNLIKELY
1685#endif
1686#if defined(JSON_HEDLEY_UNPREDICTABLE)
1687 #undef JSON_HEDLEY_UNPREDICTABLE
1688#endif
1689#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable)
1690 #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr))
1691#endif
1692#if \
1693 (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \
1694 JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \
1695 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1696# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability))
1697# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability))
1698# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability))
1699# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 )
1700# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 )
1701#elif \
1702 (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
1703 JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \
1704 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1705 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \
1706 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1707 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1708 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1709 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \
1710 JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \
1711 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \
1712 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
1713 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1714 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1715 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \
1716 JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
1717 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1718# define JSON_HEDLEY_PREDICT(expr, expected, probability) \
1719 (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)))
1720# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \
1721 (__extension__ ({ \
1722 double hedley_probability_ = (probability); \
1723 ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \
1724 }))
1725# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \
1726 (__extension__ ({ \
1727 double hedley_probability_ = (probability); \
1728 ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \
1729 }))
1730# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1)
1731# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)
1732#else
1733# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))
1734# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr))
1735# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr))
1736# define JSON_HEDLEY_LIKELY(expr) (!!(expr))
1737# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr))
1738#endif
1739#if !defined(JSON_HEDLEY_UNPREDICTABLE)
1740 #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5)
1741#endif
1742
1743#if defined(JSON_HEDLEY_MALLOC)
1744 #undef JSON_HEDLEY_MALLOC
1745#endif
1746#if \
1747 JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \
1748 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
1749 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1750 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
1751 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1752 JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
1753 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1754 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1755 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1756 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1757 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1758 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1759 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1760 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1761 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1762 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1763 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1764 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1765 #define JSON_HEDLEY_MALLOC __attribute__((__malloc__))
1766#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
1767 #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory")
1768#elif \
1769 JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
1770 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1771 #define JSON_HEDLEY_MALLOC __declspec(restrict)
1772#else
1773 #define JSON_HEDLEY_MALLOC
1774#endif
1775
1776#if defined(JSON_HEDLEY_PURE)
1777 #undef JSON_HEDLEY_PURE
1778#endif
1779#if \
1780 JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \
1781 JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \
1782 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1783 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
1784 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1785 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1786 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1787 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1788 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1789 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1790 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1791 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1792 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1793 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1794 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1795 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1796 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1797 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
1798 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1799# define JSON_HEDLEY_PURE __attribute__((__pure__))
1800#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
1801# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data")
1802#elif defined(__cplusplus) && \
1803 ( \
1804 JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \
1805 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \
1806 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \
1807 )
1808# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;")
1809#else
1810# define JSON_HEDLEY_PURE
1811#endif
1812
1813#if defined(JSON_HEDLEY_CONST)
1814 #undef JSON_HEDLEY_CONST
1815#endif
1816#if \
1817 JSON_HEDLEY_HAS_ATTRIBUTE(const) || \
1818 JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \
1819 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1820 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
1821 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1822 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1823 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1824 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1825 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1826 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1827 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1828 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1829 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1830 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1831 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1832 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1833 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1834 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
1835 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1836 #define JSON_HEDLEY_CONST __attribute__((__const__))
1837#elif \
1838 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)
1839 #define JSON_HEDLEY_CONST _Pragma("no_side_effect")
1840#else
1841 #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE
1842#endif
1843
1844#if defined(JSON_HEDLEY_RESTRICT)
1845 #undef JSON_HEDLEY_RESTRICT
1846#endif
1847#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)
1848 #define JSON_HEDLEY_RESTRICT restrict
1849#elif \
1850 JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \
1851 JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \
1852 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1853 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
1854 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1855 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1856 JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \
1857 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1858 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \
1859 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \
1860 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1861 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \
1862 JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \
1863 defined(__clang__) || \
1864 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1865 #define JSON_HEDLEY_RESTRICT __restrict
1866#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus)
1867 #define JSON_HEDLEY_RESTRICT _Restrict
1868#else
1869 #define JSON_HEDLEY_RESTRICT
1870#endif
1871
1872#if defined(JSON_HEDLEY_INLINE)
1873 #undef JSON_HEDLEY_INLINE
1874#endif
1875#if \
1876 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
1877 (defined(__cplusplus) && (__cplusplus >= 199711L))
1878 #define JSON_HEDLEY_INLINE inline
1879#elif \
1880 defined(JSON_HEDLEY_GCC_VERSION) || \
1881 JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0)
1882 #define JSON_HEDLEY_INLINE __inline__
1883#elif \
1884 JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
1885 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
1886 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1887 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \
1888 JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \
1889 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \
1890 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \
1891 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1892 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1893 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
1894 #define JSON_HEDLEY_INLINE __inline
1895#else
1896 #define JSON_HEDLEY_INLINE
1897#endif
1898
1899#if defined(JSON_HEDLEY_ALWAYS_INLINE)
1900 #undef JSON_HEDLEY_ALWAYS_INLINE
1901#endif
1902#if \
1903 JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \
1904 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
1905 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1906 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
1907 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1908 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1909 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1910 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1911 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1912 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1913 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1914 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1915 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1916 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1917 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1918 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1919 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1920 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
1921 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
1922# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE
1923#elif \
1924 JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \
1925 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1926# define JSON_HEDLEY_ALWAYS_INLINE __forceinline
1927#elif defined(__cplusplus) && \
1928 ( \
1929 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1930 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1931 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1932 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
1933 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1934 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \
1935 )
1936# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;")
1937#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1938# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced")
1939#else
1940# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE
1941#endif
1942
1943#if defined(JSON_HEDLEY_NEVER_INLINE)
1944 #undef JSON_HEDLEY_NEVER_INLINE
1945#endif
1946#if \
1947 JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \
1948 JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \
1949 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
1950 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
1951 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
1952 JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \
1953 JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \
1954 (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1955 JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \
1956 (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1957 JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \
1958 (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1959 JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \
1960 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
1961 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \
1962 JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \
1963 JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \
1964 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \
1965 JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)
1966 #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__))
1967#elif \
1968 JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \
1969 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
1970 #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
1971#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0)
1972 #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline")
1973#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)
1974 #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;")
1975#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
1976 #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never")
1977#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)
1978 #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline))
1979#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)
1980 #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)
1981#else
1982 #define JSON_HEDLEY_NEVER_INLINE
1983#endif
1984
1985#if defined(JSON_HEDLEY_PRIVATE)
1986 #undef JSON_HEDLEY_PRIVATE
1987#endif
1988#if defined(JSON_HEDLEY_PUBLIC)
1989 #undef JSON_HEDLEY_PUBLIC
1990#endif
1991#if defined(JSON_HEDLEY_IMPORT)
1992 #undef JSON_HEDLEY_IMPORT
1993#endif
1994#if defined(_WIN32) || defined(__CYGWIN__)
1995# define JSON_HEDLEY_PRIVATE
1996# define JSON_HEDLEY_PUBLIC __declspec(dllexport)
1997# define JSON_HEDLEY_IMPORT __declspec(dllimport)
1998#else
1999# if \
2000 JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \
2001 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
2002 JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \
2003 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
2004 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
2005 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
2006 ( \
2007 defined(__TI_EABI__) && \
2008 ( \
2009 (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \
2010 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \
2011 ) \
2012 ) || \
2013 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
2014# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden")))
2015# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default")))
2016# else
2017# define JSON_HEDLEY_PRIVATE
2018# define JSON_HEDLEY_PUBLIC
2019# endif
2020# define JSON_HEDLEY_IMPORT extern
2021#endif
2022
2023#if defined(JSON_HEDLEY_NO_THROW)
2024 #undef JSON_HEDLEY_NO_THROW
2025#endif
2026#if \
2027 JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \
2028 JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \
2029 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
2030 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
2031 #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__))
2032#elif \
2033 JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \
2034 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \
2035 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)
2036 #define JSON_HEDLEY_NO_THROW __declspec(nothrow)
2037#else
2038 #define JSON_HEDLEY_NO_THROW
2039#endif
2040
2041#if defined(JSON_HEDLEY_FALL_THROUGH)
2042 #undef JSON_HEDLEY_FALL_THROUGH
2043#endif
2044#if \
2045 JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \
2046 JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \
2047 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
2048 #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__))
2049#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough)
2050 #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]])
2051#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)
2052 #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]])
2053#elif defined(__fallthrough) /* SAL */
2054 #define JSON_HEDLEY_FALL_THROUGH __fallthrough
2055#else
2056 #define JSON_HEDLEY_FALL_THROUGH
2057#endif
2058
2059#if defined(JSON_HEDLEY_RETURNS_NON_NULL)
2060 #undef JSON_HEDLEY_RETURNS_NON_NULL
2061#endif
2062#if \
2063 JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \
2064 JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \
2065 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
2066 #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__))
2067#elif defined(_Ret_notnull_) /* SAL */
2068 #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_
2069#else
2070 #define JSON_HEDLEY_RETURNS_NON_NULL
2071#endif
2072
2073#if defined(JSON_HEDLEY_ARRAY_PARAM)
2074 #undef JSON_HEDLEY_ARRAY_PARAM
2075#endif
2076#if \
2077 defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
2078 !defined(__STDC_NO_VLA__) && \
2079 !defined(__cplusplus) && \
2080 !defined(JSON_HEDLEY_PGI_VERSION) && \
2081 !defined(JSON_HEDLEY_TINYC_VERSION)
2082 #define JSON_HEDLEY_ARRAY_PARAM(name) (name)
2083#else
2084 #define JSON_HEDLEY_ARRAY_PARAM(name)
2085#endif
2086
2087#if defined(JSON_HEDLEY_IS_CONSTANT)
2088 #undef JSON_HEDLEY_IS_CONSTANT
2089#endif
2090#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR)
2091 #undef JSON_HEDLEY_REQUIRE_CONSTEXPR
2092#endif
2093/* JSON_HEDLEY_IS_CONSTEXPR_ is for
2094 HEDLEY INTERNAL USE ONLY. API subject to change without notice. */
2095#if defined(JSON_HEDLEY_IS_CONSTEXPR_)
2096 #undef JSON_HEDLEY_IS_CONSTEXPR_
2097#endif
2098#if \
2099 JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \
2100 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
2101 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
2102 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \
2103 JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \
2104 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
2105 JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \
2106 (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \
2107 JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
2108 JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)
2109 #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr)
2110#endif
2111#if !defined(__cplusplus)
2112# if \
2113 JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \
2114 JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \
2115 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
2116 JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \
2117 JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \
2118 JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \
2119 JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24)
2120#if defined(__INTPTR_TYPE__)
2121 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)
2122#else
2123 #include <stdint.h>
2124 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*)
2125#endif
2126# elif \
2127 ( \
2128 defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \
2129 !defined(JSON_HEDLEY_SUNPRO_VERSION) && \
2130 !defined(JSON_HEDLEY_PGI_VERSION) && \
2131 !defined(JSON_HEDLEY_IAR_VERSION)) || \
2132 (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \
2133 JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \
2134 JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \
2135 JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \
2136 JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0)
2137#if defined(__INTPTR_TYPE__)
2138 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)
2139#else
2140 #include <stdint.h>
2141 #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0)
2142#endif
2143# elif \
2144 defined(JSON_HEDLEY_GCC_VERSION) || \
2145 defined(JSON_HEDLEY_INTEL_VERSION) || \
2146 defined(JSON_HEDLEY_TINYC_VERSION) || \
2147 defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \
2148 JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \
2149 defined(JSON_HEDLEY_TI_CL2000_VERSION) || \
2150 defined(JSON_HEDLEY_TI_CL6X_VERSION) || \
2151 defined(JSON_HEDLEY_TI_CL7X_VERSION) || \
2152 defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \
2153 defined(__clang__)
2154# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \
2155 sizeof(void) != \
2156 sizeof(*( \
2157 1 ? \
2158 ((void*) ((expr) * 0L) ) : \
2159((struct { char v[sizeof(void) * 2]; } *) 1) \
2160 ) \
2161 ) \
2162 )
2163# endif
2164#endif
2165#if defined(JSON_HEDLEY_IS_CONSTEXPR_)
2166 #if !defined(JSON_HEDLEY_IS_CONSTANT)
2167 #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr)
2168 #endif
2169 #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1))
2170#else
2171 #if !defined(JSON_HEDLEY_IS_CONSTANT)
2172 #define JSON_HEDLEY_IS_CONSTANT(expr) (0)
2173 #endif
2174 #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr)
2175#endif
2176
2177#if defined(JSON_HEDLEY_BEGIN_C_DECLS)
2178 #undef JSON_HEDLEY_BEGIN_C_DECLS
2179#endif
2180#if defined(JSON_HEDLEY_END_C_DECLS)
2181 #undef JSON_HEDLEY_END_C_DECLS
2182#endif
2183#if defined(JSON_HEDLEY_C_DECL)
2184 #undef JSON_HEDLEY_C_DECL
2185#endif
2186#if defined(__cplusplus)
2187 #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" {
2188 #define JSON_HEDLEY_END_C_DECLS }
2189 #define JSON_HEDLEY_C_DECL extern "C"
2190#else
2191 #define JSON_HEDLEY_BEGIN_C_DECLS
2192 #define JSON_HEDLEY_END_C_DECLS
2193 #define JSON_HEDLEY_C_DECL
2194#endif
2195
2196#if defined(JSON_HEDLEY_STATIC_ASSERT)
2197 #undef JSON_HEDLEY_STATIC_ASSERT
2198#endif
2199#if \
2200 !defined(__cplusplus) && ( \
2201 (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \
2202 (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \
2203 JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \
2204 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \
2205 defined(_Static_assert) \
2206 )
2207# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message)
2208#elif \
2209 (defined(__cplusplus) && (__cplusplus >= 201103L)) || \
2210 JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \
2211 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
2212# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message))
2213#else
2214# define JSON_HEDLEY_STATIC_ASSERT(expr, message)
2215#endif
2216
2217#if defined(JSON_HEDLEY_NULL)
2218 #undef JSON_HEDLEY_NULL
2219#endif
2220#if defined(__cplusplus)
2221 #if __cplusplus >= 201103L
2222 #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr)
2223 #elif defined(NULL)
2224 #define JSON_HEDLEY_NULL NULL
2225 #else
2226 #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0)
2227 #endif
2228#elif defined(NULL)
2229 #define JSON_HEDLEY_NULL NULL
2230#else
2231 #define JSON_HEDLEY_NULL ((void*) 0)
2232#endif
2233
2234#if defined(JSON_HEDLEY_MESSAGE)
2235 #undef JSON_HEDLEY_MESSAGE
2236#endif
2237#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
2238# define JSON_HEDLEY_MESSAGE(msg) \
2239 JSON_HEDLEY_DIAGNOSTIC_PUSH \
2240 JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
2241 JSON_HEDLEY_PRAGMA(message msg) \
2242 JSON_HEDLEY_DIAGNOSTIC_POP
2243#elif \
2244 JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \
2245 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
2246# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg)
2247#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0)
2248# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg)
2249#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)
2250# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
2251#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0)
2252# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))
2253#else
2254# define JSON_HEDLEY_MESSAGE(msg)
2255#endif
2256
2257#if defined(JSON_HEDLEY_WARNING)
2258 #undef JSON_HEDLEY_WARNING
2259#endif
2260#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas")
2261# define JSON_HEDLEY_WARNING(msg) \
2262 JSON_HEDLEY_DIAGNOSTIC_PUSH \
2263 JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \
2264 JSON_HEDLEY_PRAGMA(clang warning msg) \
2265 JSON_HEDLEY_DIAGNOSTIC_POP
2266#elif \
2267 JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \
2268 JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \
2269 JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)
2270# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg)
2271#elif \
2272 JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \
2273 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
2274# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg))
2275#else
2276# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg)
2277#endif
2278
2279#if defined(JSON_HEDLEY_REQUIRE)
2280 #undef JSON_HEDLEY_REQUIRE
2281#endif
2282#if defined(JSON_HEDLEY_REQUIRE_MSG)
2283 #undef JSON_HEDLEY_REQUIRE_MSG
2284#endif
2285#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if)
2286# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat")
2287# define JSON_HEDLEY_REQUIRE(expr) \
2288 JSON_HEDLEY_DIAGNOSTIC_PUSH \
2289 _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
2290 __attribute__((diagnose_if(!(expr), #expr, "error"))) \
2291 JSON_HEDLEY_DIAGNOSTIC_POP
2292# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \
2293 JSON_HEDLEY_DIAGNOSTIC_PUSH \
2294 _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \
2295 __attribute__((diagnose_if(!(expr), msg, "error"))) \
2296 JSON_HEDLEY_DIAGNOSTIC_POP
2297# else
2298# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error")))
2299# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error")))
2300# endif
2301#else
2302# define JSON_HEDLEY_REQUIRE(expr)
2303# define JSON_HEDLEY_REQUIRE_MSG(expr,msg)
2304#endif
2305
2306#if defined(JSON_HEDLEY_FLAGS)
2307 #undef JSON_HEDLEY_FLAGS
2308#endif
2309#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion"))
2310 #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__))
2311#else
2312 #define JSON_HEDLEY_FLAGS
2313#endif
2314
2315#if defined(JSON_HEDLEY_FLAGS_CAST)
2316 #undef JSON_HEDLEY_FLAGS_CAST
2317#endif
2318#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0)
2319# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \
2320 JSON_HEDLEY_DIAGNOSTIC_PUSH \
2321 _Pragma("warning(disable:188)") \
2322 ((T) (expr)); \
2323 JSON_HEDLEY_DIAGNOSTIC_POP \
2324 }))
2325#else
2326# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr)
2327#endif
2328
2329#if defined(JSON_HEDLEY_EMPTY_BASES)
2330 #undef JSON_HEDLEY_EMPTY_BASES
2331#endif
2332#if \
2333 (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \
2334 JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)
2335 #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases)
2336#else
2337 #define JSON_HEDLEY_EMPTY_BASES
2338#endif
2339
2340/* Remaining macros are deprecated. */
2341
2342#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK)
2343 #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
2344#endif
2345#if defined(__clang__)
2346 #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0)
2347#else
2348 #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)
2349#endif
2350
2351#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE)
2352 #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
2353#endif
2354#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)
2355
2356#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE)
2357 #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
2358#endif
2359#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute)
2360
2361#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN)
2362 #undef JSON_HEDLEY_CLANG_HAS_BUILTIN
2363#endif
2364#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin)
2365
2366#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE)
2367 #undef JSON_HEDLEY_CLANG_HAS_FEATURE
2368#endif
2369#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature)
2370
2371#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION)
2372 #undef JSON_HEDLEY_CLANG_HAS_EXTENSION
2373#endif
2374#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension)
2375
2376#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE)
2377 #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
2378#endif
2379#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute)
2380
2381#if defined(JSON_HEDLEY_CLANG_HAS_WARNING)
2382 #undef JSON_HEDLEY_CLANG_HAS_WARNING
2383#endif
2384#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning)
2385
2386#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */
2387
2388
2389// This file contains all internal macro definitions (except those affecting ABI)
2390// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
2391
2392// #include <nlohmann/detail/abi_macros.hpp>
2393
2394
2395// exclude unsupported compilers
2396#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)
2397 #if defined(__clang__)
2398 #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
2399 #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
2400 #endif
2401 #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
2402 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800
2403 #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
2404 #endif
2405 #endif
2406#endif
2407
2408// C++ language standard detection
2409// if the user manually specified the used c++ version this is skipped
2410#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)
2411 #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
2412 #define JSON_HAS_CPP_20
2413 #define JSON_HAS_CPP_17
2414 #define JSON_HAS_CPP_14
2415 #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
2416 #define JSON_HAS_CPP_17
2417 #define JSON_HAS_CPP_14
2418 #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
2419 #define JSON_HAS_CPP_14
2420 #endif
2421 // the cpp 11 flag is always specified because it is the minimal required version
2422 #define JSON_HAS_CPP_11
2423#endif
2424
2425#ifdef __has_include
2426 #if __has_include(<version>)
2427 #include <version>
2428 #endif
2429#endif
2430
2431#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM)
2432 #ifdef JSON_HAS_CPP_17
2433 #if defined(__cpp_lib_filesystem)
2434 #define JSON_HAS_FILESYSTEM 1
2435 #elif defined(__cpp_lib_experimental_filesystem)
2436 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
2437 #elif !defined(__has_include)
2438 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
2439 #elif __has_include(<filesystem>)
2440 #define JSON_HAS_FILESYSTEM 1
2441 #elif __has_include(<experimental/filesystem>)
2442 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1
2443 #endif
2444
2445 // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/
2446 #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8
2447 #undef JSON_HAS_FILESYSTEM
2448 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2449 #endif
2450
2451 // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support
2452 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8
2453 #undef JSON_HAS_FILESYSTEM
2454 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2455 #endif
2456
2457 // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support
2458 #if defined(__clang_major__) && __clang_major__ < 7
2459 #undef JSON_HAS_FILESYSTEM
2460 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2461 #endif
2462
2463 // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support
2464 #if defined(_MSC_VER) && _MSC_VER < 1914
2465 #undef JSON_HAS_FILESYSTEM
2466 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2467 #endif
2468
2469 // no filesystem support before iOS 13
2470 #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000
2471 #undef JSON_HAS_FILESYSTEM
2472 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2473 #endif
2474
2475 // no filesystem support before macOS Catalina
2476 #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500
2477 #undef JSON_HAS_FILESYSTEM
2478 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2479 #endif
2480 #endif
2481#endif
2482
2483#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM
2484 #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0
2485#endif
2486
2487#ifndef JSON_HAS_FILESYSTEM
2488 #define JSON_HAS_FILESYSTEM 0
2489#endif
2490
2491#ifndef JSON_HAS_THREE_WAY_COMPARISON
2492 #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \
2493 && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L
2494 #define JSON_HAS_THREE_WAY_COMPARISON 1
2495 #else
2496 #define JSON_HAS_THREE_WAY_COMPARISON 0
2497 #endif
2498#endif
2499
2500#ifndef JSON_HAS_RANGES
2501 // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error
2502 #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427
2503 #define JSON_HAS_RANGES 0
2504 #elif defined(__cpp_lib_ranges)
2505 #define JSON_HAS_RANGES 1
2506 #else
2507 #define JSON_HAS_RANGES 0
2508 #endif
2509#endif
2510
2511#ifndef JSON_HAS_STATIC_RTTI
2512 #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0
2513 #define JSON_HAS_STATIC_RTTI 1
2514 #else
2515 #define JSON_HAS_STATIC_RTTI 0
2516 #endif
2517#endif
2518
2519#ifdef JSON_HAS_CPP_17
2520 #define JSON_INLINE_VARIABLE inline
2521#else
2522 #define JSON_INLINE_VARIABLE
2523#endif
2524
2525#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address)
2526 #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]]
2527#else
2528 #define JSON_NO_UNIQUE_ADDRESS
2529#endif
2530
2531// disable documentation warnings on clang
2532#if defined(__clang__)
2533 #pragma clang diagnostic push
2534 #pragma clang diagnostic ignored "-Wdocumentation"
2535 #pragma clang diagnostic ignored "-Wdocumentation-unknown-command"
2536#endif
2537
2538// allow disabling exceptions
2539#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
2540 #define JSON_THROW(exception) throw exception
2541 #define JSON_TRY try
2542 #define JSON_CATCH(exception) catch(exception)
2543 #define JSON_INTERNAL_CATCH(exception) catch(exception)
2544#else
2545 #include <cstdlib>
2546 #define JSON_THROW(exception) std::abort()
2547 #define JSON_TRY if(true)
2548 #define JSON_CATCH(exception) if(false)
2549 #define JSON_INTERNAL_CATCH(exception) if(false)
2550#endif
2551
2552// override exception macros
2553#if defined(JSON_THROW_USER)
2554 #undef JSON_THROW
2555 #define JSON_THROW JSON_THROW_USER
2556#endif
2557#if defined(JSON_TRY_USER)
2558 #undef JSON_TRY
2559 #define JSON_TRY JSON_TRY_USER
2560#endif
2561#if defined(JSON_CATCH_USER)
2562 #undef JSON_CATCH
2563 #define JSON_CATCH JSON_CATCH_USER
2564 #undef JSON_INTERNAL_CATCH
2565 #define JSON_INTERNAL_CATCH JSON_CATCH_USER
2566#endif
2567#if defined(JSON_INTERNAL_CATCH_USER)
2568 #undef JSON_INTERNAL_CATCH
2569 #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
2570#endif
2571
2572// allow overriding assert
2573#if !defined(JSON_ASSERT)
2574 #include <cassert> // assert
2575 #define JSON_ASSERT(x) assert(x)
2576#endif
2577
2578// allow to access some private functions (needed by the test suite)
2579#if defined(JSON_TESTS_PRIVATE)
2580 #define JSON_PRIVATE_UNLESS_TESTED public
2581#else
2582 #define JSON_PRIVATE_UNLESS_TESTED private
2583#endif
2584
2590#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \
2591 template<typename BasicJsonType> \
2592 inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
2593 { \
2594 static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
2595 static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
2596 auto it = std::find_if(std::begin(m), std::end(m), \
2597 [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
2598 { \
2599 return ej_pair.first == e; \
2600 }); \
2601 j = ((it != std::end(m)) ? it : std::begin(m))->second; \
2602 } \
2603 template<typename BasicJsonType> \
2604 inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
2605 { \
2606 static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
2607 static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
2608 auto it = std::find_if(std::begin(m), std::end(m), \
2609 [&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \
2610 { \
2611 return ej_pair.second == j; \
2612 }); \
2613 e = ((it != std::end(m)) ? it : std::begin(m))->first; \
2614 }
2615
2616// Ugly macros to avoid uglier copy-paste when specializing basic_json. They
2617// may be removed in the future once the class is split.
2618
2619#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \
2620 template<template<typename, typename, typename...> class ObjectType, \
2621 template<typename, typename...> class ArrayType, \
2622 class StringType, class BooleanType, class NumberIntegerType, \
2623 class NumberUnsignedType, class NumberFloatType, \
2624 template<typename> class AllocatorType, \
2625 template<typename, typename = void> class JSONSerializer, \
2626 class BinaryType, \
2627 class CustomBaseClass>
2628
2629#define NLOHMANN_BASIC_JSON_TPL \
2630 basic_json<ObjectType, ArrayType, StringType, BooleanType, \
2631 NumberIntegerType, NumberUnsignedType, NumberFloatType, \
2632 AllocatorType, JSONSerializer, BinaryType, CustomBaseClass>
2633
2634// Macros to simplify conversion from/to types
2635
2636#define NLOHMANN_JSON_EXPAND( x ) x
2637#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME
2638#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \
2639 NLOHMANN_JSON_PASTE64, \
2640 NLOHMANN_JSON_PASTE63, \
2641 NLOHMANN_JSON_PASTE62, \
2642 NLOHMANN_JSON_PASTE61, \
2643 NLOHMANN_JSON_PASTE60, \
2644 NLOHMANN_JSON_PASTE59, \
2645 NLOHMANN_JSON_PASTE58, \
2646 NLOHMANN_JSON_PASTE57, \
2647 NLOHMANN_JSON_PASTE56, \
2648 NLOHMANN_JSON_PASTE55, \
2649 NLOHMANN_JSON_PASTE54, \
2650 NLOHMANN_JSON_PASTE53, \
2651 NLOHMANN_JSON_PASTE52, \
2652 NLOHMANN_JSON_PASTE51, \
2653 NLOHMANN_JSON_PASTE50, \
2654 NLOHMANN_JSON_PASTE49, \
2655 NLOHMANN_JSON_PASTE48, \
2656 NLOHMANN_JSON_PASTE47, \
2657 NLOHMANN_JSON_PASTE46, \
2658 NLOHMANN_JSON_PASTE45, \
2659 NLOHMANN_JSON_PASTE44, \
2660 NLOHMANN_JSON_PASTE43, \
2661 NLOHMANN_JSON_PASTE42, \
2662 NLOHMANN_JSON_PASTE41, \
2663 NLOHMANN_JSON_PASTE40, \
2664 NLOHMANN_JSON_PASTE39, \
2665 NLOHMANN_JSON_PASTE38, \
2666 NLOHMANN_JSON_PASTE37, \
2667 NLOHMANN_JSON_PASTE36, \
2668 NLOHMANN_JSON_PASTE35, \
2669 NLOHMANN_JSON_PASTE34, \
2670 NLOHMANN_JSON_PASTE33, \
2671 NLOHMANN_JSON_PASTE32, \
2672 NLOHMANN_JSON_PASTE31, \
2673 NLOHMANN_JSON_PASTE30, \
2674 NLOHMANN_JSON_PASTE29, \
2675 NLOHMANN_JSON_PASTE28, \
2676 NLOHMANN_JSON_PASTE27, \
2677 NLOHMANN_JSON_PASTE26, \
2678 NLOHMANN_JSON_PASTE25, \
2679 NLOHMANN_JSON_PASTE24, \
2680 NLOHMANN_JSON_PASTE23, \
2681 NLOHMANN_JSON_PASTE22, \
2682 NLOHMANN_JSON_PASTE21, \
2683 NLOHMANN_JSON_PASTE20, \
2684 NLOHMANN_JSON_PASTE19, \
2685 NLOHMANN_JSON_PASTE18, \
2686 NLOHMANN_JSON_PASTE17, \
2687 NLOHMANN_JSON_PASTE16, \
2688 NLOHMANN_JSON_PASTE15, \
2689 NLOHMANN_JSON_PASTE14, \
2690 NLOHMANN_JSON_PASTE13, \
2691 NLOHMANN_JSON_PASTE12, \
2692 NLOHMANN_JSON_PASTE11, \
2693 NLOHMANN_JSON_PASTE10, \
2694 NLOHMANN_JSON_PASTE9, \
2695 NLOHMANN_JSON_PASTE8, \
2696 NLOHMANN_JSON_PASTE7, \
2697 NLOHMANN_JSON_PASTE6, \
2698 NLOHMANN_JSON_PASTE5, \
2699 NLOHMANN_JSON_PASTE4, \
2700 NLOHMANN_JSON_PASTE3, \
2701 NLOHMANN_JSON_PASTE2, \
2702 NLOHMANN_JSON_PASTE1)(__VA_ARGS__))
2703#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)
2704#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)
2705#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)
2706#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4)
2707#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5)
2708#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6)
2709#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)
2710#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)
2711#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9)
2712#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)
2713#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)
2714#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)
2715#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)
2716#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)
2717#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)
2718#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)
2719#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)
2720#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)
2721#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)
2722#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)
2723#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)
2724#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)
2725#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)
2726#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)
2727#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)
2728#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)
2729#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)
2730#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)
2731#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)
2732#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)
2733#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)
2734#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)
2735#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)
2736#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)
2737#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)
2738#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)
2739#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)
2740#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)
2741#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)
2742#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40)
2743#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)
2744#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42)
2745#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43)
2746#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44)
2747#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45)
2748#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46)
2749#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47)
2750#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48)
2751#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49)
2752#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50)
2753#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51)
2754#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)
2755#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53)
2756#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54)
2757#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55)
2758#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56)
2759#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57)
2760#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58)
2761#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59)
2762#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60)
2763#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61)
2764#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62)
2765#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63)
2766
2767#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1;
2768#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);
2769#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1);
2770
2776#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \
2777 friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
2778 friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
2779
2780#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \
2781 friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
2782 friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
2783
2784#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
2785 friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
2786
2792#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \
2793 inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
2794 inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }
2795
2796#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
2797 inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }
2798
2799#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \
2800 inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \
2801 inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }
2802
2803// inspired from https://stackoverflow.com/a/26745591
2804// allows to call any std function as if (e.g. with begin):
2805// using std::begin; begin(x);
2806//
2807// it allows using the detected idiom to retrieve the return type
2808// of such an expression
2809#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \
2810 namespace detail { \
2811 using std::std_name; \
2812 \
2813 template<typename... T> \
2814 using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
2815 } \
2816 \
2817 namespace detail2 { \
2818 struct std_name##_tag \
2819 { \
2820 }; \
2821 \
2822 template<typename... T> \
2823 std_name##_tag std_name(T&&...); \
2824 \
2825 template<typename... T> \
2826 using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
2827 \
2828 template<typename... T> \
2829 struct would_call_std_##std_name \
2830 { \
2831 static constexpr auto const value = ::nlohmann::detail:: \
2832 is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \
2833 }; \
2834 } /* namespace detail2 */ \
2835 \
2836 template<typename... T> \
2837 struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...> \
2838 { \
2839 }
2840
2841#ifndef JSON_USE_IMPLICIT_CONVERSIONS
2842 #define JSON_USE_IMPLICIT_CONVERSIONS 1
2843#endif
2844
2845#if JSON_USE_IMPLICIT_CONVERSIONS
2846 #define JSON_EXPLICIT
2847#else
2848 #define JSON_EXPLICIT explicit
2849#endif
2850
2851#ifndef JSON_DISABLE_ENUM_SERIALIZATION
2852 #define JSON_DISABLE_ENUM_SERIALIZATION 0
2853#endif
2854
2855#ifndef JSON_USE_GLOBAL_UDLS
2856 #define JSON_USE_GLOBAL_UDLS 1
2857#endif
2858
2859#if JSON_HAS_THREE_WAY_COMPARISON
2860 #include <compare> // partial_ordering
2861#endif
2862
2863NLOHMANN_JSON_NAMESPACE_BEGIN
2864namespace detail
2865{
2866
2868// JSON type enumeration //
2870
2895enum class value_t : std::uint8_t
2896{
2897 null,
2898 object,
2899 array,
2900 string,
2901 boolean,
2904 number_float,
2905 binary,
2906 discarded
2907};
2908
2922#if JSON_HAS_THREE_WAY_COMPARISON
2923 inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD*
2924#else
2925 inline bool operator<(const value_t lhs, const value_t rhs) noexcept
2926#endif
2927{
2928 static constexpr std::array<std::uint8_t, 9> order = {{
2929 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,
2930 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */,
2931 6 /* binary */
2932 }
2933 };
2934
2935 const auto l_index = static_cast<std::size_t>(lhs);
2936 const auto r_index = static_cast<std::size_t>(rhs);
2937#if JSON_HAS_THREE_WAY_COMPARISON
2938 if (l_index < order.size() && r_index < order.size())
2939 {
2940 return order[l_index] <=> order[r_index]; // *NOPAD*
2941 }
2942 return std::partial_ordering::unordered;
2943#else
2944 return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];
2945#endif
2946}
2947
2948// GCC selects the built-in operator< over an operator rewritten from
2949// a user-defined spaceship operator
2950// Clang, MSVC, and ICC select the rewritten candidate
2951// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200)
2952#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__)
2953inline bool operator<(const value_t lhs, const value_t rhs) noexcept
2954{
2955 return std::is_lt(lhs <=> rhs); // *NOPAD*
2956}
2957#endif
2958
2959} // namespace detail
2960NLOHMANN_JSON_NAMESPACE_END
2961
2962// #include <nlohmann/detail/string_escape.hpp>
2963// __ _____ _____ _____
2964// __| | __| | | | JSON for Modern C++
2965// | | |__ | | | | | | version 3.11.3
2966// |_____|_____|_____|_|___| https://github.com/nlohmann/json
2967//
2968// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
2969// SPDX-License-Identifier: MIT
2970
2971
2972
2973// #include <nlohmann/detail/abi_macros.hpp>
2974
2975
2976NLOHMANN_JSON_NAMESPACE_BEGIN
2977namespace detail
2978{
2979
2993template<typename StringType>
2994inline void replace_substring(StringType& s, const StringType& f,
2995 const StringType& t)
2996{
2997 JSON_ASSERT(!f.empty());
2998 for (auto pos = s.find(f); // find first occurrence of f
2999 pos != StringType::npos; // make sure f was found
3000 s.replace(pos, f.size(), t), // replace with t, and
3001 pos = s.find(f, pos + t.size())) // find next occurrence of f
3002 {}
3003}
3004
3012template<typename StringType>
3013inline StringType escape(StringType s)
3014{
3015 replace_substring(s, StringType{"~"}, StringType{"~0"});
3016 replace_substring(s, StringType{"/"}, StringType{"~1"});
3017 return s;
3018}
3019
3027template<typename StringType>
3028static void unescape(StringType& s)
3029{
3030 replace_substring(s, StringType{"~1"}, StringType{"/"});
3031 replace_substring(s, StringType{"~0"}, StringType{"~"});
3032}
3033
3034} // namespace detail
3035NLOHMANN_JSON_NAMESPACE_END
3036
3037// #include <nlohmann/detail/input/position_t.hpp>
3038// __ _____ _____ _____
3039// __| | __| | | | JSON for Modern C++
3040// | | |__ | | | | | | version 3.11.3
3041// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3042//
3043// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3044// SPDX-License-Identifier: MIT
3045
3046
3047
3048#include <cstddef> // size_t
3049
3050// #include <nlohmann/detail/abi_macros.hpp>
3051
3052
3053NLOHMANN_JSON_NAMESPACE_BEGIN
3054namespace detail
3055{
3056
3059{
3061 std::size_t chars_read_total = 0;
3065 std::size_t lines_read = 0;
3066
3068 constexpr operator size_t() const
3069 {
3070 return chars_read_total;
3071 }
3072};
3073
3074} // namespace detail
3075NLOHMANN_JSON_NAMESPACE_END
3076
3077// #include <nlohmann/detail/macro_scope.hpp>
3078
3079// #include <nlohmann/detail/meta/cpp_future.hpp>
3080// __ _____ _____ _____
3081// __| | __| | | | JSON for Modern C++
3082// | | |__ | | | | | | version 3.11.3
3083// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3084//
3085// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3086// SPDX-FileCopyrightText: 2018 The Abseil Authors
3087// SPDX-License-Identifier: MIT
3088
3089
3090
3091#include <array> // array
3092#include <cstddef> // size_t
3093#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
3094#include <utility> // index_sequence, make_index_sequence, index_sequence_for
3095
3096// #include <nlohmann/detail/macro_scope.hpp>
3097
3098
3099NLOHMANN_JSON_NAMESPACE_BEGIN
3100namespace detail
3101{
3102
3103template<typename T>
3104using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
3105
3106#ifdef JSON_HAS_CPP_14
3107
3108// the following utilities are natively available in C++14
3109using std::enable_if_t;
3110using std::index_sequence;
3111using std::make_index_sequence;
3112using std::index_sequence_for;
3113
3114#else
3115
3116// alias templates to reduce boilerplate
3117template<bool B, typename T = void>
3118using enable_if_t = typename std::enable_if<B, T>::type;
3119
3120// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h
3121// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0.
3122
3124
3125// integer_sequence
3126//
3127// Class template representing a compile-time integer sequence. An instantiation
3128// of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its
3129// type through its template arguments (which is a common need when
3130// working with C++11 variadic templates). `absl::integer_sequence` is designed
3131// to be a drop-in replacement for C++14's `std::integer_sequence`.
3132//
3133// Example:
3134//
3135// template< class T, T... Ints >
3136// void user_function(integer_sequence<T, Ints...>);
3137//
3138// int main()
3139// {
3140// // user_function's `T` will be deduced to `int` and `Ints...`
3141// // will be deduced to `0, 1, 2, 3, 4`.
3142// user_function(make_integer_sequence<int, 5>());
3143// }
3144template <typename T, T... Ints>
3146{
3147 using value_type = T;
3148 static constexpr std::size_t size() noexcept
3149 {
3150 return sizeof...(Ints);
3151 }
3152};
3153
3154// index_sequence
3155//
3156// A helper template for an `integer_sequence` of `size_t`,
3157// `absl::index_sequence` is designed to be a drop-in replacement for C++14's
3158// `std::index_sequence`.
3159template <size_t... Ints>
3160using index_sequence = integer_sequence<size_t, Ints...>;
3161
3162namespace utility_internal
3163{
3164
3165template <typename Seq, size_t SeqSize, size_t Rem>
3166struct Extend;
3167
3168// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.
3169template <typename T, T... Ints, size_t SeqSize>
3170struct Extend<integer_sequence<T, Ints...>, SeqSize, 0>
3171{
3172 using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >;
3173};
3174
3175template <typename T, T... Ints, size_t SeqSize>
3176struct Extend<integer_sequence<T, Ints...>, SeqSize, 1>
3177{
3178 using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >;
3179};
3180
3181// Recursion helper for 'make_integer_sequence<T, N>'.
3182// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.
3183template <typename T, size_t N>
3184struct Gen
3185{
3186 using type =
3187 typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type;
3188};
3189
3190template <typename T>
3191struct Gen<T, 0>
3192{
3193 using type = integer_sequence<T>;
3194};
3195
3196} // namespace utility_internal
3197
3198// Compile-time sequences of integers
3199
3200// make_integer_sequence
3201//
3202// This template alias is equivalent to
3203// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in
3204// replacement for C++14's `std::make_integer_sequence`.
3205template <typename T, T N>
3206using make_integer_sequence = typename utility_internal::Gen<T, N>::type;
3207
3208// make_index_sequence
3209//
3210// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,
3211// and is designed to be a drop-in replacement for C++14's
3212// `std::make_index_sequence`.
3213template <size_t N>
3214using make_index_sequence = make_integer_sequence<size_t, N>;
3215
3216// index_sequence_for
3217//
3218// Converts a typename pack into an index sequence of the same length, and
3219// is designed to be a drop-in replacement for C++14's
3220// `std::index_sequence_for()`
3221template <typename... Ts>
3222using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
3223
3225
3226#endif
3227
3228// dispatch utility (taken from ranges-v3)
3229template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
3230template<> struct priority_tag<0> {};
3231
3232// taken from ranges-v3
3233template<typename T>
3235{
3236 static JSON_INLINE_VARIABLE constexpr T value{};
3237};
3238
3239#ifndef JSON_HAS_CPP_17
3240 template<typename T>
3241 constexpr T static_const<T>::value;
3242#endif
3243
3244template<typename T, typename... Args>
3245inline constexpr std::array<T, sizeof...(Args)> make_array(Args&& ... args)
3246{
3247 return std::array<T, sizeof...(Args)> {{static_cast<T>(std::forward<Args>(args))...}};
3248}
3249
3250} // namespace detail
3251NLOHMANN_JSON_NAMESPACE_END
3252
3253// #include <nlohmann/detail/meta/type_traits.hpp>
3254// __ _____ _____ _____
3255// __| | __| | | | JSON for Modern C++
3256// | | |__ | | | | | | version 3.11.3
3257// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3258//
3259// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3260// SPDX-License-Identifier: MIT
3261
3262
3263
3264#include <limits> // numeric_limits
3265#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
3266#include <utility> // declval
3267#include <tuple> // tuple
3268#include <string> // char_traits
3269
3270// #include <nlohmann/detail/iterators/iterator_traits.hpp>
3271// __ _____ _____ _____
3272// __| | __| | | | JSON for Modern C++
3273// | | |__ | | | | | | version 3.11.3
3274// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3275//
3276// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3277// SPDX-License-Identifier: MIT
3278
3279
3280
3281#include <iterator> // random_access_iterator_tag
3282
3283// #include <nlohmann/detail/abi_macros.hpp>
3284
3285// #include <nlohmann/detail/meta/void_t.hpp>
3286
3287// #include <nlohmann/detail/meta/cpp_future.hpp>
3288
3289
3290NLOHMANN_JSON_NAMESPACE_BEGIN
3291namespace detail
3292{
3293
3294template<typename It, typename = void>
3296
3297template<typename It>
3299 It,
3300 void_t<typename It::difference_type, typename It::value_type, typename It::pointer,
3301 typename It::reference, typename It::iterator_category >>
3302{
3303 using difference_type = typename It::difference_type;
3304 using value_type = typename It::value_type;
3305 using pointer = typename It::pointer;
3306 using reference = typename It::reference;
3307 using iterator_category = typename It::iterator_category;
3308};
3309
3310// This is required as some compilers implement std::iterator_traits in a way that
3311// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.
3312template<typename T, typename = void>
3314{
3315};
3316
3317template<typename T>
3318struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>
3319 : iterator_types<T>
3320{
3321};
3322
3323template<typename T>
3324struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>
3325{
3326 using iterator_category = std::random_access_iterator_tag;
3327 using value_type = T;
3328 using difference_type = ptrdiff_t;
3329 using pointer = T*;
3330 using reference = T&;
3331};
3332
3333} // namespace detail
3334NLOHMANN_JSON_NAMESPACE_END
3335
3336// #include <nlohmann/detail/macro_scope.hpp>
3337
3338// #include <nlohmann/detail/meta/call_std/begin.hpp>
3339// __ _____ _____ _____
3340// __| | __| | | | JSON for Modern C++
3341// | | |__ | | | | | | version 3.11.3
3342// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3343//
3344// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3345// SPDX-License-Identifier: MIT
3346
3347
3348
3349// #include <nlohmann/detail/macro_scope.hpp>
3350
3351
3352NLOHMANN_JSON_NAMESPACE_BEGIN
3353
3354NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin);
3355
3356NLOHMANN_JSON_NAMESPACE_END
3357
3358// #include <nlohmann/detail/meta/call_std/end.hpp>
3359// __ _____ _____ _____
3360// __| | __| | | | JSON for Modern C++
3361// | | |__ | | | | | | version 3.11.3
3362// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3363//
3364// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3365// SPDX-License-Identifier: MIT
3366
3367
3368
3369// #include <nlohmann/detail/macro_scope.hpp>
3370
3371
3372NLOHMANN_JSON_NAMESPACE_BEGIN
3373
3374NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end);
3375
3376NLOHMANN_JSON_NAMESPACE_END
3377
3378// #include <nlohmann/detail/meta/cpp_future.hpp>
3379
3380// #include <nlohmann/detail/meta/detected.hpp>
3381
3382// #include <nlohmann/json_fwd.hpp>
3383// __ _____ _____ _____
3384// __| | __| | | | JSON for Modern C++
3385// | | |__ | | | | | | version 3.11.3
3386// |_____|_____|_____|_|___| https://github.com/nlohmann/json
3387//
3388// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
3389// SPDX-License-Identifier: MIT
3390
3391#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
3392 #define INCLUDE_NLOHMANN_JSON_FWD_HPP_
3393
3394 #include <cstdint> // int64_t, uint64_t
3395 #include <map> // map
3396 #include <memory> // allocator
3397 #include <string> // string
3398 #include <vector> // vector
3399
3400 // #include <nlohmann/detail/abi_macros.hpp>
3401
3402
3408 NLOHMANN_JSON_NAMESPACE_BEGIN
3409
3417 template<typename T = void, typename SFINAE = void>
3418 struct adl_serializer;
3419
3422 template<template<typename U, typename V, typename... Args> class ObjectType =
3423 std::map,
3424 template<typename U, typename... Args> class ArrayType = std::vector,
3425 class StringType = std::string, class BooleanType = bool,
3426 class NumberIntegerType = std::int64_t,
3427 class NumberUnsignedType = std::uint64_t,
3428 class NumberFloatType = double,
3429 template<typename U> class AllocatorType = std::allocator,
3430 template<typename T, typename SFINAE = void> class JSONSerializer =
3432 class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError
3433 class CustomBaseClass = void>
3434 class basic_json;
3435
3438 template<typename RefStringType>
3439 class json_pointer;
3440
3445 using json = basic_json<>;
3446
3449 template<class Key, class T, class IgnoredLess, class Allocator>
3450 struct ordered_map;
3451
3454 using ordered_json = basic_json<nlohmann::ordered_map>;
3455
3456 NLOHMANN_JSON_NAMESPACE_END
3457
3458#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_
3459
3460
3461NLOHMANN_JSON_NAMESPACE_BEGIN
3470namespace detail
3471{
3472
3474// helpers //
3476
3477// Note to maintainers:
3478//
3479// Every trait in this file expects a non CV-qualified type.
3480// The only exceptions are in the 'aliases for detected' section
3481// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))
3482//
3483// In this case, T has to be properly CV-qualified to constraint the function arguments
3484// (e.g. to_json(BasicJsonType&, const T&))
3485
3486template<typename> struct is_basic_json : std::false_type {};
3487
3488NLOHMANN_BASIC_JSON_TPL_DECLARATION
3489struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
3490
3491// used by exceptions create() member functions
3492// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t
3493// false_type otherwise
3494template<typename BasicJsonContext>
3496 std::integral_constant < bool,
3497 is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value
3498 || std::is_same<BasicJsonContext, std::nullptr_t>::value >
3499{};
3500
3502// json_ref helpers //
3504
3505template<typename>
3506class json_ref;
3507
3508template<typename>
3509struct is_json_ref : std::false_type {};
3510
3511template<typename T>
3512struct is_json_ref<json_ref<T>> : std::true_type {};
3513
3515// aliases for detected //
3517
3518template<typename T>
3519using mapped_type_t = typename T::mapped_type;
3520
3521template<typename T>
3522using key_type_t = typename T::key_type;
3523
3524template<typename T>
3525using value_type_t = typename T::value_type;
3526
3527template<typename T>
3528using difference_type_t = typename T::difference_type;
3529
3530template<typename T>
3531using pointer_t = typename T::pointer;
3532
3533template<typename T>
3534using reference_t = typename T::reference;
3535
3536template<typename T>
3537using iterator_category_t = typename T::iterator_category;
3538
3539template<typename T, typename... Args>
3540using to_json_function = decltype(T::to_json(std::declval<Args>()...));
3541
3542template<typename T, typename... Args>
3543using from_json_function = decltype(T::from_json(std::declval<Args>()...));
3544
3545template<typename T, typename U>
3546using get_template_function = decltype(std::declval<T>().template get<U>());
3547
3548// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
3549template<typename BasicJsonType, typename T, typename = void>
3550struct has_from_json : std::false_type {};
3551
3552// trait checking if j.get<T> is valid
3553// use this trait instead of std::is_constructible or std::is_convertible,
3554// both rely on, or make use of implicit conversions, and thus fail when T
3555// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
3556template <typename BasicJsonType, typename T>
3558{
3559 static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;
3560};
3561
3562template<typename BasicJsonType, typename T>
3563struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
3564{
3565 using serializer = typename BasicJsonType::template json_serializer<T, void>;
3566
3567 static constexpr bool value =
3568 is_detected_exact<void, from_json_function, serializer,
3569 const BasicJsonType&, T&>::value;
3570};
3571
3572// This trait checks if JSONSerializer<T>::from_json(json const&) exists
3573// this overload is used for non-default-constructible user-defined-types
3574template<typename BasicJsonType, typename T, typename = void>
3575struct has_non_default_from_json : std::false_type {};
3576
3577template<typename BasicJsonType, typename T>
3578struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
3579{
3580 using serializer = typename BasicJsonType::template json_serializer<T, void>;
3581
3582 static constexpr bool value =
3583 is_detected_exact<T, from_json_function, serializer,
3584 const BasicJsonType&>::value;
3585};
3586
3587// This trait checks if BasicJsonType::json_serializer<T>::to_json exists
3588// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
3589template<typename BasicJsonType, typename T, typename = void>
3590struct has_to_json : std::false_type {};
3591
3592template<typename BasicJsonType, typename T>
3593struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>
3594{
3595 using serializer = typename BasicJsonType::template json_serializer<T, void>;
3596
3597 static constexpr bool value =
3598 is_detected_exact<void, to_json_function, serializer, BasicJsonType&,
3599 T>::value;
3600};
3601
3602template<typename T>
3603using detect_key_compare = typename T::key_compare;
3604
3605template<typename T>
3606struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {};
3607
3608// obtains the actual object key comparator
3609template<typename BasicJsonType>
3611{
3612 using object_t = typename BasicJsonType::object_t;
3613 using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
3614 using type = typename std::conditional < has_key_compare<object_t>::value,
3615 typename object_t::key_compare, object_comparator_t>::type;
3616};
3617
3618template<typename BasicJsonType>
3619using actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type;
3620
3622// char_traits //
3624
3625// Primary template of char_traits calls std char_traits
3626template<typename T>
3627struct char_traits : std::char_traits<T>
3628{};
3629
3630// Explicitly define char traits for unsigned char since it is not standard
3631template<>
3632struct char_traits<unsigned char> : std::char_traits<char>
3633{
3634 using char_type = unsigned char;
3635 using int_type = uint64_t;
3636
3637 // Redefine to_int_type function
3638 static int_type to_int_type(char_type c) noexcept
3639 {
3640 return static_cast<int_type>(c);
3641 }
3642
3643 static char_type to_char_type(int_type i) noexcept
3644 {
3645 return static_cast<char_type>(i);
3646 }
3647
3648 static constexpr int_type eof() noexcept
3649 {
3650 return static_cast<int_type>(EOF);
3651 }
3652};
3653
3654// Explicitly define char traits for signed char since it is not standard
3655template<>
3656struct char_traits<signed char> : std::char_traits<char>
3657{
3658 using char_type = signed char;
3659 using int_type = uint64_t;
3660
3661 // Redefine to_int_type function
3662 static int_type to_int_type(char_type c) noexcept
3663 {
3664 return static_cast<int_type>(c);
3665 }
3666
3667 static char_type to_char_type(int_type i) noexcept
3668 {
3669 return static_cast<char_type>(i);
3670 }
3671
3672 static constexpr int_type eof() noexcept
3673 {
3674 return static_cast<int_type>(EOF);
3675 }
3676};
3677
3679// is_ functions //
3681
3682// https://en.cppreference.com/w/cpp/types/conjunction
3683template<class...> struct conjunction : std::true_type { };
3684template<class B> struct conjunction<B> : B { };
3685template<class B, class... Bn>
3686struct conjunction<B, Bn...>
3687: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {};
3688
3689// https://en.cppreference.com/w/cpp/types/negation
3690template<class B> struct negation : std::integral_constant < bool, !B::value > { };
3691
3692// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
3693// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
3694// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
3695template <typename T>
3696struct is_default_constructible : std::is_default_constructible<T> {};
3697
3698template <typename T1, typename T2>
3699struct is_default_constructible<std::pair<T1, T2>>
3700 : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
3701
3702template <typename T1, typename T2>
3703struct is_default_constructible<const std::pair<T1, T2>>
3704 : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};
3705
3706template <typename... Ts>
3707struct is_default_constructible<std::tuple<Ts...>>
3708 : conjunction<is_default_constructible<Ts>...> {};
3709
3710template <typename... Ts>
3711struct is_default_constructible<const std::tuple<Ts...>>
3712 : conjunction<is_default_constructible<Ts>...> {};
3713
3714template <typename T, typename... Args>
3715struct is_constructible : std::is_constructible<T, Args...> {};
3716
3717template <typename T1, typename T2>
3718struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {};
3719
3720template <typename T1, typename T2>
3721struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {};
3722
3723template <typename... Ts>
3724struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {};
3725
3726template <typename... Ts>
3727struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {};
3728
3729template<typename T, typename = void>
3730struct is_iterator_traits : std::false_type {};
3731
3732template<typename T>
3734{
3735 private:
3736 using traits = iterator_traits<T>;
3737
3738 public:
3739 static constexpr auto value =
3740 is_detected<value_type_t, traits>::value &&
3741 is_detected<difference_type_t, traits>::value &&
3742 is_detected<pointer_t, traits>::value &&
3743 is_detected<iterator_category_t, traits>::value &&
3744 is_detected<reference_t, traits>::value;
3745};
3746
3747template<typename T>
3749{
3750 private:
3751 using t_ref = typename std::add_lvalue_reference<T>::type;
3752
3753 using iterator = detected_t<result_of_begin, t_ref>;
3754 using sentinel = detected_t<result_of_end, t_ref>;
3755
3756 // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator
3757 // and https://en.cppreference.com/w/cpp/iterator/sentinel_for
3758 // but reimplementing these would be too much work, as a lot of other concepts are used underneath
3759 static constexpr auto is_iterator_begin =
3761
3762 public:
3763 static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin;
3764};
3765
3766template<typename R>
3767using iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>;
3768
3769template<typename T>
3770using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;
3771
3772// The following implementation of is_complete_type is taken from
3773// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/
3774// and is written by Xiang Fan who agreed to using it in this library.
3775
3776template<typename T, typename = void>
3777struct is_complete_type : std::false_type {};
3778
3779template<typename T>
3780struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};
3781
3782template<typename BasicJsonType, typename CompatibleObjectType,
3783 typename = void>
3784struct is_compatible_object_type_impl : std::false_type {};
3785
3786template<typename BasicJsonType, typename CompatibleObjectType>
3788 BasicJsonType, CompatibleObjectType,
3789 enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&
3790 is_detected<key_type_t, CompatibleObjectType>::value >>
3791{
3792 using object_t = typename BasicJsonType::object_t;
3793
3794 // macOS's is_constructible does not play well with nonesuch...
3795 static constexpr bool value =
3796 is_constructible<typename object_t::key_type,
3797 typename CompatibleObjectType::key_type>::value &&
3798 is_constructible<typename object_t::mapped_type,
3799 typename CompatibleObjectType::mapped_type>::value;
3800};
3801
3802template<typename BasicJsonType, typename CompatibleObjectType>
3804 : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};
3805
3806template<typename BasicJsonType, typename ConstructibleObjectType,
3807 typename = void>
3808struct is_constructible_object_type_impl : std::false_type {};
3809
3810template<typename BasicJsonType, typename ConstructibleObjectType>
3812 BasicJsonType, ConstructibleObjectType,
3813 enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&
3814 is_detected<key_type_t, ConstructibleObjectType>::value >>
3815{
3816 using object_t = typename BasicJsonType::object_t;
3817
3818 static constexpr bool value =
3820 (std::is_move_assignable<ConstructibleObjectType>::value ||
3821 std::is_copy_assignable<ConstructibleObjectType>::value) &&
3822 (is_constructible<typename ConstructibleObjectType::key_type,
3823 typename object_t::key_type>::value &&
3824 std::is_same <
3825 typename object_t::mapped_type,
3826 typename ConstructibleObjectType::mapped_type >::value)) ||
3827 (has_from_json<BasicJsonType,
3828 typename ConstructibleObjectType::mapped_type>::value ||
3830 BasicJsonType,
3831 typename ConstructibleObjectType::mapped_type >::value);
3832};
3833
3834template<typename BasicJsonType, typename ConstructibleObjectType>
3836 : is_constructible_object_type_impl<BasicJsonType,
3837 ConstructibleObjectType> {};
3838
3839template<typename BasicJsonType, typename CompatibleStringType>
3845
3846template<typename BasicJsonType, typename ConstructibleStringType>
3848{
3849 // launder type through decltype() to fix compilation failure on ICPC
3850#ifdef __INTEL_COMPILER
3851 using laundered_type = decltype(std::declval<ConstructibleStringType>());
3852#else
3853 using laundered_type = ConstructibleStringType;
3854#endif
3855
3856 static constexpr auto value =
3857 conjunction <
3859 is_detected_exact<typename BasicJsonType::string_t::value_type,
3860 value_type_t, laundered_type >>::value;
3861};
3862
3863template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
3864struct is_compatible_array_type_impl : std::false_type {};
3865
3866template<typename BasicJsonType, typename CompatibleArrayType>
3868 BasicJsonType, CompatibleArrayType,
3869 enable_if_t <
3870 is_detected<iterator_t, CompatibleArrayType>::value&&
3871 is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&
3872// special case for types like std::filesystem::path whose iterator's value_type are themselves
3873// c.f. https://github.com/nlohmann/json/pull/3073
3874 !std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>
3875{
3876 static constexpr bool value =
3877 is_constructible<BasicJsonType,
3878 range_value_t<CompatibleArrayType>>::value;
3879};
3880
3881template<typename BasicJsonType, typename CompatibleArrayType>
3883 : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};
3884
3885template<typename BasicJsonType, typename ConstructibleArrayType, typename = void>
3886struct is_constructible_array_type_impl : std::false_type {};
3887
3888template<typename BasicJsonType, typename ConstructibleArrayType>
3890 BasicJsonType, ConstructibleArrayType,
3891 enable_if_t<std::is_same<ConstructibleArrayType,
3892 typename BasicJsonType::value_type>::value >>
3893 : std::true_type {};
3894
3895template<typename BasicJsonType, typename ConstructibleArrayType>
3897 BasicJsonType, ConstructibleArrayType,
3898 enable_if_t < !std::is_same<ConstructibleArrayType,
3899 typename BasicJsonType::value_type>::value&&
3900 !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
3901 is_default_constructible<ConstructibleArrayType>::value&&
3902(std::is_move_assignable<ConstructibleArrayType>::value ||
3903 std::is_copy_assignable<ConstructibleArrayType>::value)&&
3904is_detected<iterator_t, ConstructibleArrayType>::value&&
3905is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&
3906is_detected<range_value_t, ConstructibleArrayType>::value&&
3907// special case for types like std::filesystem::path whose iterator's value_type are themselves
3908// c.f. https://github.com/nlohmann/json/pull/3073
3909!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&
3911 detected_t<range_value_t, ConstructibleArrayType >>::value >>
3912{
3913 using value_type = range_value_t<ConstructibleArrayType>;
3914
3915 static constexpr bool value =
3916 std::is_same<value_type,
3917 typename BasicJsonType::array_t::value_type>::value ||
3918 has_from_json<BasicJsonType,
3919 value_type>::value ||
3921 BasicJsonType,
3922 value_type >::value;
3923};
3924
3925template<typename BasicJsonType, typename ConstructibleArrayType>
3927 : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};
3928
3929template<typename RealIntegerType, typename CompatibleNumberIntegerType,
3930 typename = void>
3931struct is_compatible_integer_type_impl : std::false_type {};
3932
3933template<typename RealIntegerType, typename CompatibleNumberIntegerType>
3935 RealIntegerType, CompatibleNumberIntegerType,
3936 enable_if_t < std::is_integral<RealIntegerType>::value&&
3937 std::is_integral<CompatibleNumberIntegerType>::value&&
3938 !std::is_same<bool, CompatibleNumberIntegerType>::value >>
3939{
3940 // is there an assert somewhere on overflows?
3941 using RealLimits = std::numeric_limits<RealIntegerType>;
3942 using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;
3943
3944 static constexpr auto value =
3945 is_constructible<RealIntegerType,
3946 CompatibleNumberIntegerType>::value &&
3947 CompatibleLimits::is_integer &&
3948 RealLimits::is_signed == CompatibleLimits::is_signed;
3949};
3950
3951template<typename RealIntegerType, typename CompatibleNumberIntegerType>
3953 : is_compatible_integer_type_impl<RealIntegerType,
3954 CompatibleNumberIntegerType> {};
3955
3956template<typename BasicJsonType, typename CompatibleType, typename = void>
3957struct is_compatible_type_impl: std::false_type {};
3958
3959template<typename BasicJsonType, typename CompatibleType>
3961 BasicJsonType, CompatibleType,
3962 enable_if_t<is_complete_type<CompatibleType>::value >>
3963{
3964 static constexpr bool value =
3966};
3967
3968template<typename BasicJsonType, typename CompatibleType>
3970 : is_compatible_type_impl<BasicJsonType, CompatibleType> {};
3971
3972template<typename T1, typename T2>
3973struct is_constructible_tuple : std::false_type {};
3974
3975template<typename T1, typename... Args>
3976struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};
3977
3978template<typename BasicJsonType, typename T>
3979struct is_json_iterator_of : std::false_type {};
3980
3981template<typename BasicJsonType>
3982struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {};
3983
3984template<typename BasicJsonType>
3985struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type
3986{};
3987
3988// checks if a given type T is a template specialization of Primary
3989template<template <typename...> class Primary, typename T>
3990struct is_specialization_of : std::false_type {};
3991
3992template<template <typename...> class Primary, typename... Args>
3993struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};
3994
3995template<typename T>
3997
3998// checks if A and B are comparable using Compare functor
3999template<typename Compare, typename A, typename B, typename = void>
4000struct is_comparable : std::false_type {};
4001
4002template<typename Compare, typename A, typename B>
4003struct is_comparable<Compare, A, B, void_t<
4004decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())),
4005decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))
4006>> : std::true_type {};
4007
4008template<typename T>
4009using detect_is_transparent = typename T::is_transparent;
4010
4011// type trait to check if KeyType can be used as object key (without a BasicJsonType)
4012// see is_usable_as_basic_json_key_type below
4013template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
4014 bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
4015using is_usable_as_key_type = typename std::conditional <
4017 && !(ExcludeObjectKeyType && std::is_same<KeyType,
4018 ObjectKeyType>::value)
4019 && (!RequireTransparentComparator
4020 || is_detected <detect_is_transparent, Comparator>::value)
4021 && !is_json_pointer<KeyType>::value,
4022 std::true_type,
4023 std::false_type >::type;
4024
4025// type trait to check if KeyType can be used as object key
4026// true if:
4027// - KeyType is comparable with BasicJsonType::object_t::key_type
4028// - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type
4029// - the comparator is transparent or RequireTransparentComparator is false
4030// - KeyType is not a JSON iterator or json_pointer
4031template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,
4032 bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
4033using is_usable_as_basic_json_key_type = typename std::conditional <
4034 is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
4035 typename BasicJsonType::object_t::key_type, KeyTypeCVRef,
4036 RequireTransparentComparator, ExcludeObjectKeyType>::value
4038 std::true_type,
4039 std::false_type >::type;
4040
4041template<typename ObjectType, typename KeyType>
4042using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));
4043
4044// type trait to check if object_t has an erase() member functions accepting KeyType
4045template<typename BasicJsonType, typename KeyType>
4046using has_erase_with_key_type = typename std::conditional <
4047 is_detected <
4048 detect_erase_with_key_type,
4049 typename BasicJsonType::object_t, KeyType >::value,
4050 std::true_type,
4051 std::false_type >::type;
4052
4053// a naive helper to check if a type is an ordered_map (exploits the fact that
4054// ordered_map inherits capacity() from std::vector)
4055template <typename T>
4057{
4058 using one = char;
4059
4060 struct two
4061 {
4062 char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
4063 };
4064
4065 template <typename C> static one test( decltype(&C::capacity) ) ;
4066 template <typename C> static two test(...);
4067
4068 enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
4069};
4070
4071// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
4072template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
4073T conditional_static_cast(U value)
4074{
4075 return static_cast<T>(value);
4076}
4077
4078template<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0>
4079T conditional_static_cast(U value)
4080{
4081 return value;
4082}
4083
4084template<typename... Types>
4085using all_integral = conjunction<std::is_integral<Types>...>;
4086
4087template<typename... Types>
4088using all_signed = conjunction<std::is_signed<Types>...>;
4089
4090template<typename... Types>
4091using all_unsigned = conjunction<std::is_unsigned<Types>...>;
4092
4093// there's a disjunction trait in another PR; replace when merged
4094template<typename... Types>
4095using same_sign = std::integral_constant < bool,
4096 all_signed<Types...>::value || all_unsigned<Types...>::value >;
4097
4098template<typename OfType, typename T>
4099using never_out_of_range = std::integral_constant < bool,
4100 (std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType)))
4101 || (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >;
4102
4103template<typename OfType, typename T,
4104 bool OfTypeSigned = std::is_signed<OfType>::value,
4105 bool TSigned = std::is_signed<T>::value>
4107
4108template<typename OfType, typename T>
4109struct value_in_range_of_impl2<OfType, T, false, false>
4110{
4111 static constexpr bool test(T val)
4112 {
4113 using CommonType = typename std::common_type<OfType, T>::type;
4114 return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
4115 }
4116};
4117
4118template<typename OfType, typename T>
4119struct value_in_range_of_impl2<OfType, T, true, false>
4120{
4121 static constexpr bool test(T val)
4122 {
4123 using CommonType = typename std::common_type<OfType, T>::type;
4124 return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
4125 }
4126};
4127
4128template<typename OfType, typename T>
4129struct value_in_range_of_impl2<OfType, T, false, true>
4130{
4131 static constexpr bool test(T val)
4132 {
4133 using CommonType = typename std::common_type<OfType, T>::type;
4134 return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
4135 }
4136};
4137
4138template<typename OfType, typename T>
4139struct value_in_range_of_impl2<OfType, T, true, true>
4140{
4141 static constexpr bool test(T val)
4142 {
4143 using CommonType = typename std::common_type<OfType, T>::type;
4144 return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)())
4145 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
4146 }
4147};
4148
4149template<typename OfType, typename T,
4150 bool NeverOutOfRange = never_out_of_range<OfType, T>::value,
4151 typename = detail::enable_if_t<all_integral<OfType, T>::value>>
4153
4154template<typename OfType, typename T>
4155struct value_in_range_of_impl1<OfType, T, false>
4156{
4157 static constexpr bool test(T val)
4158 {
4160 }
4161};
4162
4163template<typename OfType, typename T>
4164struct value_in_range_of_impl1<OfType, T, true>
4165{
4166 static constexpr bool test(T /*val*/)
4167 {
4168 return true;
4169 }
4170};
4171
4172template<typename OfType, typename T>
4173inline constexpr bool value_in_range_of(T val)
4174{
4176}
4177
4178template<bool Value>
4179using bool_constant = std::integral_constant<bool, Value>;
4180
4182// is_c_string
4184
4185namespace impl
4186{
4187
4188template<typename T>
4189inline constexpr bool is_c_string()
4190{
4191 using TUnExt = typename std::remove_extent<T>::type;
4192 using TUnCVExt = typename std::remove_cv<TUnExt>::type;
4193 using TUnPtr = typename std::remove_pointer<T>::type;
4194 using TUnCVPtr = typename std::remove_cv<TUnPtr>::type;
4195 return
4196 (std::is_array<T>::value && std::is_same<TUnCVExt, char>::value)
4197 || (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value);
4198}
4199
4200} // namespace impl
4201
4202// checks whether T is a [cv] char */[cv] char[] C string
4203template<typename T>
4204struct is_c_string : bool_constant<impl::is_c_string<T>()> {};
4205
4206template<typename T>
4207using is_c_string_uncvref = is_c_string<uncvref_t<T>>;
4208
4210// is_transparent
4212
4213namespace impl
4214{
4215
4216template<typename T>
4217inline constexpr bool is_transparent()
4218{
4219 return is_detected<detect_is_transparent, T>::value;
4220}
4221
4222} // namespace impl
4223
4224// checks whether T has a member named is_transparent
4225template<typename T>
4226struct is_transparent : bool_constant<impl::is_transparent<T>()> {};
4227
4229
4230} // namespace detail
4231NLOHMANN_JSON_NAMESPACE_END
4232
4233// #include <nlohmann/detail/string_concat.hpp>
4234// __ _____ _____ _____
4235// __| | __| | | | JSON for Modern C++
4236// | | |__ | | | | | | version 3.11.3
4237// |_____|_____|_____|_|___| https://github.com/nlohmann/json
4238//
4239// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
4240// SPDX-License-Identifier: MIT
4241
4242
4243
4244#include <cstring> // strlen
4245#include <string> // string
4246#include <utility> // forward
4247
4248// #include <nlohmann/detail/meta/cpp_future.hpp>
4249
4250// #include <nlohmann/detail/meta/detected.hpp>
4251
4252
4253NLOHMANN_JSON_NAMESPACE_BEGIN
4254namespace detail
4255{
4256
4257inline std::size_t concat_length()
4258{
4259 return 0;
4260}
4261
4262template<typename... Args>
4263inline std::size_t concat_length(const char* cstr, const Args& ... rest);
4264
4265template<typename StringType, typename... Args>
4266inline std::size_t concat_length(const StringType& str, const Args& ... rest);
4267
4268template<typename... Args>
4269inline std::size_t concat_length(const char /*c*/, const Args& ... rest)
4270{
4271 return 1 + concat_length(rest...);
4272}
4273
4274template<typename... Args>
4275inline std::size_t concat_length(const char* cstr, const Args& ... rest)
4276{
4277 // cppcheck-suppress ignoredReturnValue
4278 return ::strlen(cstr) + concat_length(rest...);
4279}
4280
4281template<typename StringType, typename... Args>
4282inline std::size_t concat_length(const StringType& str, const Args& ... rest)
4283{
4284 return str.size() + concat_length(rest...);
4285}
4286
4287template<typename OutStringType>
4288inline void concat_into(OutStringType& /*out*/)
4289{}
4290
4291template<typename StringType, typename Arg>
4292using string_can_append = decltype(std::declval<StringType&>().append(std::declval < Arg && > ()));
4293
4294template<typename StringType, typename Arg>
4295using detect_string_can_append = is_detected<string_can_append, StringType, Arg>;
4296
4297template<typename StringType, typename Arg>
4298using string_can_append_op = decltype(std::declval<StringType&>() += std::declval < Arg && > ());
4299
4300template<typename StringType, typename Arg>
4301using detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>;
4302
4303template<typename StringType, typename Arg>
4304using string_can_append_iter = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().begin(), std::declval<const Arg&>().end()));
4305
4306template<typename StringType, typename Arg>
4307using detect_string_can_append_iter = is_detected<string_can_append_iter, StringType, Arg>;
4308
4309template<typename StringType, typename Arg>
4310using string_can_append_data = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().data(), std::declval<const Arg&>().size()));
4311
4312template<typename StringType, typename Arg>
4313using detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>;
4314
4315template < typename OutStringType, typename Arg, typename... Args,
4316 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
4317 && detect_string_can_append_op<OutStringType, Arg>::value, int > = 0 >
4318inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest);
4319
4320template < typename OutStringType, typename Arg, typename... Args,
4321 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
4322 && !detect_string_can_append_op<OutStringType, Arg>::value
4323 && detect_string_can_append_iter<OutStringType, Arg>::value, int > = 0 >
4324inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
4325
4326template < typename OutStringType, typename Arg, typename... Args,
4327 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
4328 && !detect_string_can_append_op<OutStringType, Arg>::value
4329 && !detect_string_can_append_iter<OutStringType, Arg>::value
4330 && detect_string_can_append_data<OutStringType, Arg>::value, int > = 0 >
4331inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
4332
4333template<typename OutStringType, typename Arg, typename... Args,
4334 enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0>
4335inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest)
4336{
4337 out.append(std::forward<Arg>(arg));
4338 concat_into(out, std::forward<Args>(rest)...);
4339}
4340
4341template < typename OutStringType, typename Arg, typename... Args,
4342 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
4343 && detect_string_can_append_op<OutStringType, Arg>::value, int > >
4344inline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest)
4345{
4346 out += std::forward<Arg>(arg);
4347 concat_into(out, std::forward<Args>(rest)...);
4348}
4349
4350template < typename OutStringType, typename Arg, typename... Args,
4351 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
4352 && !detect_string_can_append_op<OutStringType, Arg>::value
4353 && detect_string_can_append_iter<OutStringType, Arg>::value, int > >
4354inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
4355{
4356 out.append(arg.begin(), arg.end());
4357 concat_into(out, std::forward<Args>(rest)...);
4358}
4359
4360template < typename OutStringType, typename Arg, typename... Args,
4361 enable_if_t < !detect_string_can_append<OutStringType, Arg>::value
4362 && !detect_string_can_append_op<OutStringType, Arg>::value
4363 && !detect_string_can_append_iter<OutStringType, Arg>::value
4364 && detect_string_can_append_data<OutStringType, Arg>::value, int > >
4365inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
4366{
4367 out.append(arg.data(), arg.size());
4368 concat_into(out, std::forward<Args>(rest)...);
4369}
4370
4371template<typename OutStringType = std::string, typename... Args>
4372inline OutStringType concat(Args && ... args)
4373{
4374 OutStringType str;
4375 str.reserve(concat_length(args...));
4376 concat_into(str, std::forward<Args>(args)...);
4377 return str;
4378}
4379
4380} // namespace detail
4381NLOHMANN_JSON_NAMESPACE_END
4382
4383
4384NLOHMANN_JSON_NAMESPACE_BEGIN
4385namespace detail
4386{
4387
4389// exceptions //
4391
4394class exception : public std::exception
4395{
4396 public:
4398 const char* what() const noexcept override
4399 {
4400 return m.what();
4401 }
4402
4404 const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
4405
4406 protected:
4407 JSON_HEDLEY_NON_NULL(3)
4408 exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing)
4409
4410 static std::string name(const std::string& ename, int id_)
4411 {
4412 return concat("[json.exception.", ename, '.', std::to_string(id_), "] ");
4413 }
4414
4415 static std::string diagnostics(std::nullptr_t /*leaf_element*/)
4416 {
4417 return "";
4418 }
4419
4420 template<typename BasicJsonType>
4421 static std::string diagnostics(const BasicJsonType* leaf_element)
4422 {
4423#if JSON_DIAGNOSTICS
4424 std::vector<std::string> tokens;
4425 for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent)
4426 {
4427 switch (current->m_parent->type())
4428 {
4429 case value_t::array:
4430 {
4431 for (std::size_t i = 0; i < current->m_parent->m_data.m_value.array->size(); ++i)
4432 {
4433 if (&current->m_parent->m_data.m_value.array->operator[](i) == current)
4434 {
4435 tokens.emplace_back(std::to_string(i));
4436 break;
4437 }
4438 }
4439 break;
4440 }
4441
4442 case value_t::object:
4443 {
4444 for (const auto& element : *current->m_parent->m_data.m_value.object)
4445 {
4446 if (&element.second == current)
4447 {
4448 tokens.emplace_back(element.first.c_str());
4449 break;
4450 }
4451 }
4452 break;
4453 }
4454
4455 case value_t::null: // LCOV_EXCL_LINE
4456 case value_t::string: // LCOV_EXCL_LINE
4457 case value_t::boolean: // LCOV_EXCL_LINE
4458 case value_t::number_integer: // LCOV_EXCL_LINE
4459 case value_t::number_unsigned: // LCOV_EXCL_LINE
4460 case value_t::number_float: // LCOV_EXCL_LINE
4461 case value_t::binary: // LCOV_EXCL_LINE
4462 case value_t::discarded: // LCOV_EXCL_LINE
4463 default: // LCOV_EXCL_LINE
4464 break; // LCOV_EXCL_LINE
4465 }
4466 }
4467
4468 if (tokens.empty())
4469 {
4470 return "";
4471 }
4472
4473 auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},
4474 [](const std::string & a, const std::string & b)
4475 {
4476 return concat(a, '/', detail::escape(b));
4477 });
4478 return concat('(', str, ") ");
4479#else
4480 static_cast<void>(leaf_element);
4481 return "";
4482#endif
4483 }
4484
4485 private:
4487 std::runtime_error m;
4488};
4489
4493{
4494 public:
4504 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4505 static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)
4506 {
4507 const std::string w = concat(exception::name("parse_error", id_), "parse error",
4508 position_string(pos), ": ", exception::diagnostics(context), what_arg);
4509 return {id_, pos.chars_read_total, w.c_str()};
4510 }
4511
4512 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4513 static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)
4514 {
4515 const std::string w = concat(exception::name("parse_error", id_), "parse error",
4516 (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""),
4517 ": ", exception::diagnostics(context), what_arg);
4518 return {id_, byte_, w.c_str()};
4519 }
4520
4530 const std::size_t byte;
4531
4532 private:
4533 parse_error(int id_, std::size_t byte_, const char* what_arg)
4534 : exception(id_, what_arg), byte(byte_) {}
4535
4536 static std::string position_string(const position_t& pos)
4537 {
4538 return concat(" at line ", std::to_string(pos.lines_read + 1),
4539 ", column ", std::to_string(pos.chars_read_current_line));
4540 }
4541};
4542
4546{
4547 public:
4548 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4549 static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context)
4550 {
4551 const std::string w = concat(exception::name("invalid_iterator", id_), exception::diagnostics(context), what_arg);
4552 return {id_, w.c_str()};
4553 }
4554
4555 private:
4556 JSON_HEDLEY_NON_NULL(3)
4557 invalid_iterator(int id_, const char* what_arg)
4558 : exception(id_, what_arg) {}
4559};
4560
4563class type_error : public exception
4564{
4565 public:
4566 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4567 static type_error create(int id_, const std::string& what_arg, BasicJsonContext context)
4568 {
4569 const std::string w = concat(exception::name("type_error", id_), exception::diagnostics(context), what_arg);
4570 return {id_, w.c_str()};
4571 }
4572
4573 private:
4574 JSON_HEDLEY_NON_NULL(3)
4575 type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
4576};
4577
4581{
4582 public:
4583 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4584 static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context)
4585 {
4586 const std::string w = concat(exception::name("out_of_range", id_), exception::diagnostics(context), what_arg);
4587 return {id_, w.c_str()};
4588 }
4589
4590 private:
4591 JSON_HEDLEY_NON_NULL(3)
4592 out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}
4593};
4594
4598{
4599 public:
4600 template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
4601 static other_error create(int id_, const std::string& what_arg, BasicJsonContext context)
4602 {
4603 const std::string w = concat(exception::name("other_error", id_), exception::diagnostics(context), what_arg);
4604 return {id_, w.c_str()};
4605 }
4606
4607 private:
4608 JSON_HEDLEY_NON_NULL(3)
4609 other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}
4610};
4611
4612} // namespace detail
4613NLOHMANN_JSON_NAMESPACE_END
4614
4615// #include <nlohmann/detail/macro_scope.hpp>
4616
4617// #include <nlohmann/detail/meta/cpp_future.hpp>
4618
4619// #include <nlohmann/detail/meta/identity_tag.hpp>
4620// __ _____ _____ _____
4621// __| | __| | | | JSON for Modern C++
4622// | | |__ | | | | | | version 3.11.3
4623// |_____|_____|_____|_|___| https://github.com/nlohmann/json
4624//
4625// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
4626// SPDX-License-Identifier: MIT
4627
4628
4629
4630// #include <nlohmann/detail/abi_macros.hpp>
4631
4632
4633NLOHMANN_JSON_NAMESPACE_BEGIN
4634namespace detail
4635{
4636
4637// dispatching helper struct
4638template <class T> struct identity_tag {};
4639
4640} // namespace detail
4641NLOHMANN_JSON_NAMESPACE_END
4642
4643// #include <nlohmann/detail/meta/std_fs.hpp>
4644// __ _____ _____ _____
4645// __| | __| | | | JSON for Modern C++
4646// | | |__ | | | | | | version 3.11.3
4647// |_____|_____|_____|_|___| https://github.com/nlohmann/json
4648//
4649// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
4650// SPDX-License-Identifier: MIT
4651
4652
4653
4654// #include <nlohmann/detail/macro_scope.hpp>
4655
4656
4657#if JSON_HAS_EXPERIMENTAL_FILESYSTEM
4658#include <experimental/filesystem>
4659NLOHMANN_JSON_NAMESPACE_BEGIN
4660namespace detail
4661{
4662namespace std_fs = std::experimental::filesystem;
4663} // namespace detail
4664NLOHMANN_JSON_NAMESPACE_END
4665#elif JSON_HAS_FILESYSTEM
4666#include <filesystem>
4667NLOHMANN_JSON_NAMESPACE_BEGIN
4668namespace detail
4669{
4670namespace std_fs = std::filesystem;
4671} // namespace detail
4672NLOHMANN_JSON_NAMESPACE_END
4673#endif
4674
4675// #include <nlohmann/detail/meta/type_traits.hpp>
4676
4677// #include <nlohmann/detail/string_concat.hpp>
4678
4679// #include <nlohmann/detail/value_t.hpp>
4680
4681
4682NLOHMANN_JSON_NAMESPACE_BEGIN
4683namespace detail
4684{
4685
4686template<typename BasicJsonType>
4687inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
4688{
4689 if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
4690 {
4691 JSON_THROW(type_error::create(302, concat("type must be null, but is ", j.type_name()), &j));
4692 }
4693 n = nullptr;
4694}
4695
4696// overloads for basic_json template parameters
4697template < typename BasicJsonType, typename ArithmeticType,
4698 enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
4699 !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
4700 int > = 0 >
4701void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
4702{
4703 switch (static_cast<value_t>(j))
4704 {
4706 {
4707 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
4708 break;
4709 }
4711 {
4712 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
4713 break;
4714 }
4716 {
4717 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
4718 break;
4719 }
4720
4721 case value_t::null:
4722 case value_t::object:
4723 case value_t::array:
4724 case value_t::string:
4725 case value_t::boolean:
4726 case value_t::binary:
4727 case value_t::discarded:
4728 default:
4729 JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
4730 }
4731}
4732
4733template<typename BasicJsonType>
4734inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
4735{
4736 if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
4737 {
4738 JSON_THROW(type_error::create(302, concat("type must be boolean, but is ", j.type_name()), &j));
4739 }
4740 b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();
4741}
4742
4743template<typename BasicJsonType>
4744inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
4745{
4746 if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
4747 {
4748 JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
4749 }
4750 s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
4751}
4752
4753template <
4754 typename BasicJsonType, typename StringType,
4755 enable_if_t <
4756 std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
4757 && is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value
4758 && !std::is_same<typename BasicJsonType::string_t, StringType>::value
4759 && !is_json_ref<StringType>::value, int > = 0 >
4760inline void from_json(const BasicJsonType& j, StringType& s)
4761{
4762 if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
4763 {
4764 JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
4765 }
4766
4767 s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
4768}
4769
4770template<typename BasicJsonType>
4771inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
4772{
4773 get_arithmetic_value(j, val);
4774}
4775
4776template<typename BasicJsonType>
4777inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
4778{
4779 get_arithmetic_value(j, val);
4780}
4781
4782template<typename BasicJsonType>
4783inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
4784{
4785 get_arithmetic_value(j, val);
4786}
4787
4788#if !JSON_DISABLE_ENUM_SERIALIZATION
4789template<typename BasicJsonType, typename EnumType,
4790 enable_if_t<std::is_enum<EnumType>::value, int> = 0>
4791inline void from_json(const BasicJsonType& j, EnumType& e)
4792{
4793 typename std::underlying_type<EnumType>::type val;
4794 get_arithmetic_value(j, val);
4795 e = static_cast<EnumType>(val);
4796}
4797#endif // JSON_DISABLE_ENUM_SERIALIZATION
4798
4799// forward_list doesn't have an insert method
4800template<typename BasicJsonType, typename T, typename Allocator,
4801 enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
4802inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
4803{
4804 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
4805 {
4806 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
4807 }
4808 l.clear();
4809 std::transform(j.rbegin(), j.rend(),
4810 std::front_inserter(l), [](const BasicJsonType & i)
4811 {
4812 return i.template get<T>();
4813 });
4814}
4815
4816// valarray doesn't have an insert method
4817template<typename BasicJsonType, typename T,
4818 enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
4819inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
4820{
4821 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
4822 {
4823 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
4824 }
4825 l.resize(j.size());
4826 std::transform(j.begin(), j.end(), std::begin(l),
4827 [](const BasicJsonType & elem)
4828 {
4829 return elem.template get<T>();
4830 });
4831}
4832
4833template<typename BasicJsonType, typename T, std::size_t N>
4834auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
4835-> decltype(j.template get<T>(), void())
4836{
4837 for (std::size_t i = 0; i < N; ++i)
4838 {
4839 arr[i] = j.at(i).template get<T>();
4840 }
4841}
4842
4843template<typename BasicJsonType>
4844inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
4845{
4846 arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
4847}
4848
4849template<typename BasicJsonType, typename T, std::size_t N>
4850auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
4851 priority_tag<2> /*unused*/)
4852-> decltype(j.template get<T>(), void())
4853{
4854 for (std::size_t i = 0; i < N; ++i)
4855 {
4856 arr[i] = j.at(i).template get<T>();
4857 }
4858}
4859
4860template<typename BasicJsonType, typename ConstructibleArrayType,
4861 enable_if_t<
4862 std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
4863 int> = 0>
4864auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
4865-> decltype(
4866 arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
4867 j.template get<typename ConstructibleArrayType::value_type>(),
4868 void())
4869{
4870 using std::end;
4871
4872 ConstructibleArrayType ret;
4873 ret.reserve(j.size());
4874 std::transform(j.begin(), j.end(),
4875 std::inserter(ret, end(ret)), [](const BasicJsonType & i)
4876 {
4877 // get<BasicJsonType>() returns *this, this won't call a from_json
4878 // method when value_type is BasicJsonType
4879 return i.template get<typename ConstructibleArrayType::value_type>();
4880 });
4881 arr = std::move(ret);
4882}
4883
4884template<typename BasicJsonType, typename ConstructibleArrayType,
4885 enable_if_t<
4886 std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
4887 int> = 0>
4888inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
4889 priority_tag<0> /*unused*/)
4890{
4891 using std::end;
4892
4893 ConstructibleArrayType ret;
4894 std::transform(
4895 j.begin(), j.end(), std::inserter(ret, end(ret)),
4896 [](const BasicJsonType & i)
4897 {
4898 // get<BasicJsonType>() returns *this, this won't call a from_json
4899 // method when value_type is BasicJsonType
4900 return i.template get<typename ConstructibleArrayType::value_type>();
4901 });
4902 arr = std::move(ret);
4903}
4904
4905template < typename BasicJsonType, typename ConstructibleArrayType,
4906 enable_if_t <
4907 is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
4908 !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
4909 !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
4910 !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
4911 !is_basic_json<ConstructibleArrayType>::value,
4912 int > = 0 >
4913auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
4914-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),
4915j.template get<typename ConstructibleArrayType::value_type>(),
4916void())
4917{
4918 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
4919 {
4920 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
4921 }
4922
4923 from_json_array_impl(j, arr, priority_tag<3> {});
4924}
4925
4926template < typename BasicJsonType, typename T, std::size_t... Idx >
4927std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j,
4928 identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/)
4929{
4930 return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } };
4931}
4932
4933template < typename BasicJsonType, typename T, std::size_t N >
4934auto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag)
4935-> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {}))
4936{
4937 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
4938 {
4939 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
4940 }
4941
4942 return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {});
4943}
4944
4945template<typename BasicJsonType>
4946inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
4947{
4948 if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
4949 {
4950 JSON_THROW(type_error::create(302, concat("type must be binary, but is ", j.type_name()), &j));
4951 }
4952
4953 bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
4954}
4955
4956template<typename BasicJsonType, typename ConstructibleObjectType,
4957 enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
4958inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
4959{
4960 if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
4961 {
4962 JSON_THROW(type_error::create(302, concat("type must be object, but is ", j.type_name()), &j));
4963 }
4964
4965 ConstructibleObjectType ret;
4966 const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
4967 using value_type = typename ConstructibleObjectType::value_type;
4968 std::transform(
4969 inner_object->begin(), inner_object->end(),
4970 std::inserter(ret, ret.begin()),
4971 [](typename BasicJsonType::object_t::value_type const & p)
4972 {
4973 return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
4974 });
4975 obj = std::move(ret);
4976}
4977
4978// overload for arithmetic types, not chosen for basic_json template arguments
4979// (BooleanType, etc..); note: Is it really necessary to provide explicit
4980// overloads for boolean_t etc. in case of a custom BooleanType which is not
4981// an arithmetic type?
4982template < typename BasicJsonType, typename ArithmeticType,
4983 enable_if_t <
4984 std::is_arithmetic<ArithmeticType>::value&&
4985 !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
4986 !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
4987 !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
4988 !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
4989 int > = 0 >
4990inline void from_json(const BasicJsonType& j, ArithmeticType& val)
4991{
4992 switch (static_cast<value_t>(j))
4993 {
4995 {
4996 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());
4997 break;
4998 }
5000 {
5001 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());
5002 break;
5003 }
5005 {
5006 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());
5007 break;
5008 }
5009 case value_t::boolean:
5010 {
5011 val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());
5012 break;
5013 }
5014
5015 case value_t::null:
5016 case value_t::object:
5017 case value_t::array:
5018 case value_t::string:
5019 case value_t::binary:
5020 case value_t::discarded:
5021 default:
5022 JSON_THROW(type_error::create(302, concat("type must be number, but is ", j.type_name()), &j));
5023 }
5024}
5025
5026template<typename BasicJsonType, typename... Args, std::size_t... Idx>
5027std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)
5028{
5029 return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);
5030}
5031
5032template < typename BasicJsonType, class A1, class A2 >
5033std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)
5034{
5035 return {std::forward<BasicJsonType>(j).at(0).template get<A1>(),
5036 std::forward<BasicJsonType>(j).at(1).template get<A2>()};
5037}
5038
5039template<typename BasicJsonType, typename A1, typename A2>
5040inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)
5041{
5042 p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {});
5043}
5044
5045template<typename BasicJsonType, typename... Args>
5046std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
5047{
5048 return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
5049}
5050
5051template<typename BasicJsonType, typename... Args>
5052inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
5053{
5054 t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
5055}
5056
5057template<typename BasicJsonType, typename TupleRelated>
5058auto from_json(BasicJsonType&& j, TupleRelated&& t)
5059-> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {}))
5060{
5061 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
5062 {
5063 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
5064 }
5065
5066 return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});
5067}
5068
5069template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
5070 typename = enable_if_t < !std::is_constructible <
5071 typename BasicJsonType::string_t, Key >::value >>
5072inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
5073{
5074 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
5075 {
5076 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
5077 }
5078 m.clear();
5079 for (const auto& p : j)
5080 {
5081 if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
5082 {
5083 JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
5084 }
5085 m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
5086 }
5087}
5088
5089template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
5090 typename = enable_if_t < !std::is_constructible <
5091 typename BasicJsonType::string_t, Key >::value >>
5092inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
5093{
5094 if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
5095 {
5096 JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
5097 }
5098 m.clear();
5099 for (const auto& p : j)
5100 {
5101 if (JSON_HEDLEY_UNLIKELY(!p.is_array()))
5102 {
5103 JSON_THROW(type_error::create(302, concat("type must be array, but is ", p.type_name()), &j));
5104 }
5105 m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
5106 }
5107}
5108
5109#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
5110template<typename BasicJsonType>
5111inline void from_json(const BasicJsonType& j, std_fs::path& p)
5112{
5113 if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
5114 {
5115 JSON_THROW(type_error::create(302, concat("type must be string, but is ", j.type_name()), &j));
5116 }
5117 p = *j.template get_ptr<const typename BasicJsonType::string_t*>();
5118}
5119#endif
5120
5122{
5123 template<typename BasicJsonType, typename T>
5124 auto operator()(const BasicJsonType& j, T&& val) const
5125 noexcept(noexcept(from_json(j, std::forward<T>(val))))
5126 -> decltype(from_json(j, std::forward<T>(val)))
5127 {
5128 return from_json(j, std::forward<T>(val));
5129 }
5130};
5131
5132} // namespace detail
5133
5134#ifndef JSON_HAS_CPP_17
5138namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
5139{
5140#endif
5141JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers)
5143#ifndef JSON_HAS_CPP_17
5144} // namespace
5145#endif
5146
5147NLOHMANN_JSON_NAMESPACE_END
5148
5149// #include <nlohmann/detail/conversions/to_json.hpp>
5150// __ _____ _____ _____
5151// __| | __| | | | JSON for Modern C++
5152// | | |__ | | | | | | version 3.11.3
5153// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5154//
5155// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
5156// SPDX-License-Identifier: MIT
5157
5158
5159
5160#include <algorithm> // copy
5161#include <iterator> // begin, end
5162#include <string> // string
5163#include <tuple> // tuple, get
5164#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
5165#include <utility> // move, forward, declval, pair
5166#include <valarray> // valarray
5167#include <vector> // vector
5168
5169// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
5170// __ _____ _____ _____
5171// __| | __| | | | JSON for Modern C++
5172// | | |__ | | | | | | version 3.11.3
5173// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5174//
5175// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
5176// SPDX-License-Identifier: MIT
5177
5178
5179
5180#include <cstddef> // size_t
5181#include <iterator> // input_iterator_tag
5182#include <string> // string, to_string
5183#include <tuple> // tuple_size, get, tuple_element
5184#include <utility> // move
5185
5186#if JSON_HAS_RANGES
5187 #include <ranges> // enable_borrowed_range
5188#endif
5189
5190// #include <nlohmann/detail/abi_macros.hpp>
5191
5192// #include <nlohmann/detail/meta/type_traits.hpp>
5193
5194// #include <nlohmann/detail/value_t.hpp>
5195
5196
5197NLOHMANN_JSON_NAMESPACE_BEGIN
5198namespace detail
5199{
5200
5201template<typename string_type>
5202void int_to_string( string_type& target, std::size_t value )
5203{
5204 // For ADL
5205 using std::to_string;
5206 target = to_string(value);
5207}
5208template<typename IteratorType> class iteration_proxy_value
5209{
5210 public:
5211 using difference_type = std::ptrdiff_t;
5213 using pointer = value_type *;
5214 using reference = value_type &;
5215 using iterator_category = std::input_iterator_tag;
5216 using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
5217
5218 private:
5220 IteratorType anchor{};
5222 std::size_t array_index = 0;
5224 mutable std::size_t array_index_last = 0;
5226 mutable string_type array_index_str = "0";
5228 string_type empty_str{};
5229
5230 public:
5231 explicit iteration_proxy_value() = default;
5232 explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0)
5233 noexcept(std::is_nothrow_move_constructible<IteratorType>::value
5234 && std::is_nothrow_default_constructible<string_type>::value)
5235 : anchor(std::move(it))
5236 , array_index(array_index_)
5237 {}
5238
5239 iteration_proxy_value(iteration_proxy_value const&) = default;
5240 iteration_proxy_value& operator=(iteration_proxy_value const&) = default;
5241 // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions
5242 iteration_proxy_value(iteration_proxy_value&&)
5243 noexcept(std::is_nothrow_move_constructible<IteratorType>::value
5244 && std::is_nothrow_move_constructible<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
5245 iteration_proxy_value& operator=(iteration_proxy_value&&)
5246 noexcept(std::is_nothrow_move_assignable<IteratorType>::value
5247 && std::is_nothrow_move_assignable<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
5248 ~iteration_proxy_value() = default;
5249
5251 const iteration_proxy_value& operator*() const
5252 {
5253 return *this;
5254 }
5255
5258 {
5259 ++anchor;
5260 ++array_index;
5261
5262 return *this;
5263 }
5264
5265 iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp)
5266 {
5268 ++anchor;
5269 ++array_index;
5270 return tmp;
5271 }
5272
5275 {
5276 return anchor == o.anchor;
5277 }
5278
5281 {
5282 return anchor != o.anchor;
5283 }
5284
5286 const string_type& key() const
5287 {
5288 JSON_ASSERT(anchor.m_object != nullptr);
5289
5290 switch (anchor.m_object->type())
5291 {
5292 // use integer array index as key
5293 case value_t::array:
5294 {
5296 {
5297 int_to_string( array_index_str, array_index );
5299 }
5300 return array_index_str;
5301 }
5302
5303 // use key from the object
5304 case value_t::object:
5305 return anchor.key();
5306
5307 // use an empty key for all primitive types
5308 case value_t::null:
5309 case value_t::string:
5310 case value_t::boolean:
5314 case value_t::binary:
5315 case value_t::discarded:
5316 default:
5317 return empty_str;
5318 }
5319 }
5320
5322 typename IteratorType::reference value() const
5323 {
5324 return anchor.value();
5325 }
5326};
5327
5329template<typename IteratorType> class iteration_proxy
5330{
5331 private:
5333 typename IteratorType::pointer container = nullptr;
5334
5335 public:
5336 explicit iteration_proxy() = default;
5337
5339 explicit iteration_proxy(typename IteratorType::reference cont) noexcept
5340 : container(&cont) {}
5341
5342 iteration_proxy(iteration_proxy const&) = default;
5343 iteration_proxy& operator=(iteration_proxy const&) = default;
5344 iteration_proxy(iteration_proxy&&) noexcept = default;
5345 iteration_proxy& operator=(iteration_proxy&&) noexcept = default;
5346 ~iteration_proxy() = default;
5347
5349 iteration_proxy_value<IteratorType> begin() const noexcept
5350 {
5352 }
5353
5359};
5360
5361// Structured Bindings Support
5362// For further reference see https://blog.tartanllama.xyz/structured-bindings/
5363// And see https://github.com/nlohmann/json/pull/1391
5364template<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>
5365auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())
5366{
5367 return i.key();
5368}
5369// Structured Bindings Support
5370// For further reference see https://blog.tartanllama.xyz/structured-bindings/
5371// And see https://github.com/nlohmann/json/pull/1391
5372template<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>
5373auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())
5374{
5375 return i.value();
5376}
5377
5378} // namespace detail
5379NLOHMANN_JSON_NAMESPACE_END
5380
5381// The Addition to the STD Namespace is required to add
5382// Structured Bindings Support to the iteration_proxy_value class
5383// For further reference see https://blog.tartanllama.xyz/structured-bindings/
5384// And see https://github.com/nlohmann/json/pull/1391
5385namespace std
5386{
5387
5388#if defined(__clang__)
5389 // Fix: https://github.com/nlohmann/json/issues/1401
5390 #pragma clang diagnostic push
5391 #pragma clang diagnostic ignored "-Wmismatched-tags"
5392#endif
5393template<typename IteratorType>
5394class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp)
5395 : public std::integral_constant<std::size_t, 2> {};
5396
5397template<std::size_t N, typename IteratorType>
5398class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> // NOLINT(cert-dcl58-cpp)
5399{
5400 public:
5401 using type = decltype(
5402 get<N>(std::declval <
5403 ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
5404};
5405#if defined(__clang__)
5406 #pragma clang diagnostic pop
5407#endif
5408
5409} // namespace std
5410
5411#if JSON_HAS_RANGES
5412 template <typename IteratorType>
5413 inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy<IteratorType>> = true;
5414#endif
5415
5416// #include <nlohmann/detail/macro_scope.hpp>
5417
5418// #include <nlohmann/detail/meta/cpp_future.hpp>
5419
5420// #include <nlohmann/detail/meta/std_fs.hpp>
5421
5422// #include <nlohmann/detail/meta/type_traits.hpp>
5423
5424// #include <nlohmann/detail/value_t.hpp>
5425
5426
5427NLOHMANN_JSON_NAMESPACE_BEGIN
5428namespace detail
5429{
5430
5432// constructors //
5434
5435/*
5436 * Note all external_constructor<>::construct functions need to call
5437 * j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an
5438 * allocated value (e.g., a string). See bug issue
5439 * https://github.com/nlohmann/json/issues/2865 for more information.
5440 */
5441
5442template<value_t> struct external_constructor;
5443
5444template<>
5446{
5447 template<typename BasicJsonType>
5448 static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept
5449 {
5450 j.m_data.m_value.destroy(j.m_data.m_type);
5451 j.m_data.m_type = value_t::boolean;
5452 j.m_data.m_value = b;
5453 j.assert_invariant();
5454 }
5455};
5456
5457template<>
5459{
5460 template<typename BasicJsonType>
5461 static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
5462 {
5463 j.m_data.m_value.destroy(j.m_data.m_type);
5464 j.m_data.m_type = value_t::string;
5465 j.m_data.m_value = s;
5466 j.assert_invariant();
5467 }
5468
5469 template<typename BasicJsonType>
5470 static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
5471 {
5472 j.m_data.m_value.destroy(j.m_data.m_type);
5473 j.m_data.m_type = value_t::string;
5474 j.m_data.m_value = std::move(s);
5475 j.assert_invariant();
5476 }
5477
5478 template < typename BasicJsonType, typename CompatibleStringType,
5479 enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
5480 int > = 0 >
5481 static void construct(BasicJsonType& j, const CompatibleStringType& str)
5482 {
5483 j.m_data.m_value.destroy(j.m_data.m_type);
5484 j.m_data.m_type = value_t::string;
5485 j.m_data.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
5486 j.assert_invariant();
5487 }
5488};
5489
5490template<>
5492{
5493 template<typename BasicJsonType>
5494 static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
5495 {
5496 j.m_data.m_value.destroy(j.m_data.m_type);
5497 j.m_data.m_type = value_t::binary;
5498 j.m_data.m_value = typename BasicJsonType::binary_t(b);
5499 j.assert_invariant();
5500 }
5501
5502 template<typename BasicJsonType>
5503 static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
5504 {
5505 j.m_data.m_value.destroy(j.m_data.m_type);
5506 j.m_data.m_type = value_t::binary;
5507 j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b));
5508 j.assert_invariant();
5509 }
5510};
5511
5512template<>
5514{
5515 template<typename BasicJsonType>
5516 static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept
5517 {
5518 j.m_data.m_value.destroy(j.m_data.m_type);
5519 j.m_data.m_type = value_t::number_float;
5520 j.m_data.m_value = val;
5521 j.assert_invariant();
5522 }
5523};
5524
5525template<>
5527{
5528 template<typename BasicJsonType>
5529 static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept
5530 {
5531 j.m_data.m_value.destroy(j.m_data.m_type);
5532 j.m_data.m_type = value_t::number_unsigned;
5533 j.m_data.m_value = val;
5534 j.assert_invariant();
5535 }
5536};
5537
5538template<>
5540{
5541 template<typename BasicJsonType>
5542 static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept
5543 {
5544 j.m_data.m_value.destroy(j.m_data.m_type);
5545 j.m_data.m_type = value_t::number_integer;
5546 j.m_data.m_value = val;
5547 j.assert_invariant();
5548 }
5549};
5550
5551template<>
5553{
5554 template<typename BasicJsonType>
5555 static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
5556 {
5557 j.m_data.m_value.destroy(j.m_data.m_type);
5558 j.m_data.m_type = value_t::array;
5559 j.m_data.m_value = arr;
5560 j.set_parents();
5561 j.assert_invariant();
5562 }
5563
5564 template<typename BasicJsonType>
5565 static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
5566 {
5567 j.m_data.m_value.destroy(j.m_data.m_type);
5568 j.m_data.m_type = value_t::array;
5569 j.m_data.m_value = std::move(arr);
5570 j.set_parents();
5571 j.assert_invariant();
5572 }
5573
5574 template < typename BasicJsonType, typename CompatibleArrayType,
5575 enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
5576 int > = 0 >
5577 static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
5578 {
5579 using std::begin;
5580 using std::end;
5581
5582 j.m_data.m_value.destroy(j.m_data.m_type);
5583 j.m_data.m_type = value_t::array;
5584 j.m_data.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
5585 j.set_parents();
5586 j.assert_invariant();
5587 }
5588
5589 template<typename BasicJsonType>
5590 static void construct(BasicJsonType& j, const std::vector<bool>& arr)
5591 {
5592 j.m_data.m_value.destroy(j.m_data.m_type);
5593 j.m_data.m_type = value_t::array;
5594 j.m_data.m_value = value_t::array;
5595 j.m_data.m_value.array->reserve(arr.size());
5596 for (const bool x : arr)
5597 {
5598 j.m_data.m_value.array->push_back(x);
5599 j.set_parent(j.m_data.m_value.array->back());
5600 }
5601 j.assert_invariant();
5602 }
5603
5604 template<typename BasicJsonType, typename T,
5605 enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
5606 static void construct(BasicJsonType& j, const std::valarray<T>& arr)
5607 {
5608 j.m_data.m_value.destroy(j.m_data.m_type);
5609 j.m_data.m_type = value_t::array;
5610 j.m_data.m_value = value_t::array;
5611 j.m_data.m_value.array->resize(arr.size());
5612 if (arr.size() > 0)
5613 {
5614 std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin());
5615 }
5616 j.set_parents();
5617 j.assert_invariant();
5618 }
5619};
5620
5621template<>
5623{
5624 template<typename BasicJsonType>
5625 static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
5626 {
5627 j.m_data.m_value.destroy(j.m_data.m_type);
5628 j.m_data.m_type = value_t::object;
5629 j.m_data.m_value = obj;
5630 j.set_parents();
5631 j.assert_invariant();
5632 }
5633
5634 template<typename BasicJsonType>
5635 static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
5636 {
5637 j.m_data.m_value.destroy(j.m_data.m_type);
5638 j.m_data.m_type = value_t::object;
5639 j.m_data.m_value = std::move(obj);
5640 j.set_parents();
5641 j.assert_invariant();
5642 }
5643
5644 template < typename BasicJsonType, typename CompatibleObjectType,
5645 enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >
5646 static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
5647 {
5648 using std::begin;
5649 using std::end;
5650
5651 j.m_data.m_value.destroy(j.m_data.m_type);
5652 j.m_data.m_type = value_t::object;
5653 j.m_data.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
5654 j.set_parents();
5655 j.assert_invariant();
5656 }
5657};
5658
5660// to_json //
5662
5663template<typename BasicJsonType, typename T,
5664 enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
5665inline void to_json(BasicJsonType& j, T b) noexcept
5666{
5668}
5669
5670template < typename BasicJsonType, typename BoolRef,
5671 enable_if_t <
5672 ((std::is_same<std::vector<bool>::reference, BoolRef>::value
5673 && !std::is_same <std::vector<bool>::reference, typename BasicJsonType::boolean_t&>::value)
5674 || (std::is_same<std::vector<bool>::const_reference, BoolRef>::value
5675 && !std::is_same <detail::uncvref_t<std::vector<bool>::const_reference>,
5676 typename BasicJsonType::boolean_t >::value))
5677 && std::is_convertible<const BoolRef&, typename BasicJsonType::boolean_t>::value, int > = 0 >
5678inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept
5679{
5680 external_constructor<value_t::boolean>::construct(j, static_cast<typename BasicJsonType::boolean_t>(b));
5681}
5682
5683template<typename BasicJsonType, typename CompatibleString,
5684 enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
5685inline void to_json(BasicJsonType& j, const CompatibleString& s)
5686{
5687 external_constructor<value_t::string>::construct(j, s);
5688}
5689
5690template<typename BasicJsonType>
5691inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
5692{
5693 external_constructor<value_t::string>::construct(j, std::move(s));
5694}
5695
5696template<typename BasicJsonType, typename FloatType,
5697 enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
5698inline void to_json(BasicJsonType& j, FloatType val) noexcept
5699{
5700 external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
5701}
5702
5703template<typename BasicJsonType, typename CompatibleNumberUnsignedType,
5704 enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
5705inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
5706{
5707 external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
5708}
5709
5710template<typename BasicJsonType, typename CompatibleNumberIntegerType,
5711 enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
5712inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
5713{
5714 external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
5715}
5716
5717#if !JSON_DISABLE_ENUM_SERIALIZATION
5718template<typename BasicJsonType, typename EnumType,
5719 enable_if_t<std::is_enum<EnumType>::value, int> = 0>
5720inline void to_json(BasicJsonType& j, EnumType e) noexcept
5721{
5722 using underlying_type = typename std::underlying_type<EnumType>::type;
5723 external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
5724}
5725#endif // JSON_DISABLE_ENUM_SERIALIZATION
5726
5727template<typename BasicJsonType>
5728inline void to_json(BasicJsonType& j, const std::vector<bool>& e)
5729{
5730 external_constructor<value_t::array>::construct(j, e);
5731}
5732
5733template < typename BasicJsonType, typename CompatibleArrayType,
5734 enable_if_t < is_compatible_array_type<BasicJsonType,
5735 CompatibleArrayType>::value&&
5736 !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
5737 !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
5738 !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
5739 !is_basic_json<CompatibleArrayType>::value,
5740 int > = 0 >
5741inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
5742{
5743 external_constructor<value_t::array>::construct(j, arr);
5744}
5745
5746template<typename BasicJsonType>
5747inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
5748{
5749 external_constructor<value_t::binary>::construct(j, bin);
5750}
5751
5752template<typename BasicJsonType, typename T,
5753 enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
5754inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
5755{
5756 external_constructor<value_t::array>::construct(j, std::move(arr));
5757}
5758
5759template<typename BasicJsonType>
5760inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
5761{
5762 external_constructor<value_t::array>::construct(j, std::move(arr));
5763}
5764
5765template < typename BasicJsonType, typename CompatibleObjectType,
5766 enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >
5767inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
5768{
5769 external_constructor<value_t::object>::construct(j, obj);
5770}
5771
5772template<typename BasicJsonType>
5773inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
5774{
5775 external_constructor<value_t::object>::construct(j, std::move(obj));
5776}
5777
5778template <
5779 typename BasicJsonType, typename T, std::size_t N,
5780 enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,
5781 const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
5782 int > = 0 >
5783inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
5784{
5785 external_constructor<value_t::array>::construct(j, arr);
5786}
5787
5788template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 >
5789inline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)
5790{
5791 j = { p.first, p.second };
5792}
5793
5794// for https://github.com/nlohmann/json/pull/1134
5795template<typename BasicJsonType, typename T,
5796 enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
5797inline void to_json(BasicJsonType& j, const T& b)
5798{
5799 j = { {b.key(), b.value()} };
5800}
5801
5802template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
5803inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
5804{
5805 j = { std::get<Idx>(t)... };
5806}
5807
5808template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>
5809inline void to_json(BasicJsonType& j, const T& t)
5810{
5811 to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});
5812}
5813
5814#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
5815template<typename BasicJsonType>
5816inline void to_json(BasicJsonType& j, const std_fs::path& p)
5817{
5818 j = p.string();
5819}
5820#endif
5821
5823{
5824 template<typename BasicJsonType, typename T>
5825 auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
5826 -> decltype(to_json(j, std::forward<T>(val)), void())
5827 {
5828 return to_json(j, std::forward<T>(val));
5829 }
5830};
5831} // namespace detail
5832
5833#ifndef JSON_HAS_CPP_17
5837namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
5838{
5839#endif
5840JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers)
5842#ifndef JSON_HAS_CPP_17
5843} // namespace
5844#endif
5845
5846NLOHMANN_JSON_NAMESPACE_END
5847
5848// #include <nlohmann/detail/meta/identity_tag.hpp>
5849
5850
5851NLOHMANN_JSON_NAMESPACE_BEGIN
5852
5854template<typename ValueType, typename>
5856{
5859 template<typename BasicJsonType, typename TargetType = ValueType>
5860 static auto from_json(BasicJsonType && j, TargetType& val) noexcept(
5861 noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))
5862 -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())
5863 {
5864 ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
5865 }
5866
5869 template<typename BasicJsonType, typename TargetType = ValueType>
5870 static auto from_json(BasicJsonType && j) noexcept(
5871 noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {})))
5872 -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}))
5873 {
5874 return ::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {});
5875 }
5876
5879 template<typename BasicJsonType, typename TargetType = ValueType>
5880 static auto to_json(BasicJsonType& j, TargetType && val) noexcept(
5881 noexcept(::nlohmann::to_json(j, std::forward<TargetType>(val))))
5882 -> decltype(::nlohmann::to_json(j, std::forward<TargetType>(val)), void())
5883 {
5884 ::nlohmann::to_json(j, std::forward<TargetType>(val));
5885 }
5886};
5887
5888NLOHMANN_JSON_NAMESPACE_END
5889
5890// #include <nlohmann/byte_container_with_subtype.hpp>
5891// __ _____ _____ _____
5892// __| | __| | | | JSON for Modern C++
5893// | | |__ | | | | | | version 3.11.3
5894// |_____|_____|_____|_|___| https://github.com/nlohmann/json
5895//
5896// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
5897// SPDX-License-Identifier: MIT
5898
5899
5900
5901#include <cstdint> // uint8_t, uint64_t
5902#include <tuple> // tie
5903#include <utility> // move
5904
5905// #include <nlohmann/detail/abi_macros.hpp>
5906
5907
5908NLOHMANN_JSON_NAMESPACE_BEGIN
5909
5912template<typename BinaryType>
5913class byte_container_with_subtype : public BinaryType
5914{
5915 public:
5916 using container_type = BinaryType;
5917 using subtype_type = std::uint64_t;
5918
5920 byte_container_with_subtype() noexcept(noexcept(container_type()))
5921 : container_type()
5922 {}
5923
5925 byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b)))
5926 : container_type(b)
5927 {}
5928
5930 byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b))))
5931 : container_type(std::move(b))
5932 {}
5933
5935 byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b)))
5936 : container_type(b)
5937 , m_subtype(subtype_)
5938 , m_has_subtype(true)
5939 {}
5940
5942 byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b))))
5943 : container_type(std::move(b))
5944 , m_subtype(subtype_)
5945 , m_has_subtype(true)
5946 {}
5947
5948 bool operator==(const byte_container_with_subtype& rhs) const
5949 {
5950 return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==
5951 std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);
5952 }
5953
5954 bool operator!=(const byte_container_with_subtype& rhs) const
5955 {
5956 return !(rhs == *this);
5957 }
5958
5961 void set_subtype(subtype_type subtype_) noexcept
5962 {
5963 m_subtype = subtype_;
5964 m_has_subtype = true;
5965 }
5966
5969 constexpr subtype_type subtype() const noexcept
5970 {
5971 return m_has_subtype ? m_subtype : static_cast<subtype_type>(-1);
5972 }
5973
5976 constexpr bool has_subtype() const noexcept
5977 {
5978 return m_has_subtype;
5979 }
5980
5983 void clear_subtype() noexcept
5984 {
5985 m_subtype = 0;
5986 m_has_subtype = false;
5987 }
5988
5989 private:
5990 subtype_type m_subtype = 0;
5991 bool m_has_subtype = false;
5992};
5993
5994NLOHMANN_JSON_NAMESPACE_END
5995
5996// #include <nlohmann/detail/conversions/from_json.hpp>
5997
5998// #include <nlohmann/detail/conversions/to_json.hpp>
5999
6000// #include <nlohmann/detail/exceptions.hpp>
6001
6002// #include <nlohmann/detail/hash.hpp>
6003// __ _____ _____ _____
6004// __| | __| | | | JSON for Modern C++
6005// | | |__ | | | | | | version 3.11.3
6006// |_____|_____|_____|_|___| https://github.com/nlohmann/json
6007//
6008// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
6009// SPDX-License-Identifier: MIT
6010
6011
6012
6013#include <cstdint> // uint8_t
6014#include <cstddef> // size_t
6015#include <functional> // hash
6016
6017// #include <nlohmann/detail/abi_macros.hpp>
6018
6019// #include <nlohmann/detail/value_t.hpp>
6020
6021
6022NLOHMANN_JSON_NAMESPACE_BEGIN
6023namespace detail
6024{
6025
6026// boost::hash_combine
6027inline std::size_t combine(std::size_t seed, std::size_t h) noexcept
6028{
6029 seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);
6030 return seed;
6031}
6032
6044template<typename BasicJsonType>
6045std::size_t hash(const BasicJsonType& j)
6046{
6047 using string_t = typename BasicJsonType::string_t;
6048 using number_integer_t = typename BasicJsonType::number_integer_t;
6049 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
6050 using number_float_t = typename BasicJsonType::number_float_t;
6051
6052 const auto type = static_cast<std::size_t>(j.type());
6053 switch (j.type())
6054 {
6055 case BasicJsonType::value_t::null:
6056 case BasicJsonType::value_t::discarded:
6057 {
6058 return combine(type, 0);
6059 }
6060
6061 case BasicJsonType::value_t::object:
6062 {
6063 auto seed = combine(type, j.size());
6064 for (const auto& element : j.items())
6065 {
6066 const auto h = std::hash<string_t> {}(element.key());
6067 seed = combine(seed, h);
6068 seed = combine(seed, hash(element.value()));
6069 }
6070 return seed;
6071 }
6072
6073 case BasicJsonType::value_t::array:
6074 {
6075 auto seed = combine(type, j.size());
6076 for (const auto& element : j)
6077 {
6078 seed = combine(seed, hash(element));
6079 }
6080 return seed;
6081 }
6082
6083 case BasicJsonType::value_t::string:
6084 {
6085 const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());
6086 return combine(type, h);
6087 }
6088
6089 case BasicJsonType::value_t::boolean:
6090 {
6091 const auto h = std::hash<bool> {}(j.template get<bool>());
6092 return combine(type, h);
6093 }
6094
6095 case BasicJsonType::value_t::number_integer:
6096 {
6097 const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());
6098 return combine(type, h);
6099 }
6100
6101 case BasicJsonType::value_t::number_unsigned:
6102 {
6103 const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());
6104 return combine(type, h);
6105 }
6106
6107 case BasicJsonType::value_t::number_float:
6108 {
6109 const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());
6110 return combine(type, h);
6111 }
6112
6113 case BasicJsonType::value_t::binary:
6114 {
6115 auto seed = combine(type, j.get_binary().size());
6116 const auto h = std::hash<bool> {}(j.get_binary().has_subtype());
6117 seed = combine(seed, h);
6118 seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype()));
6119 for (const auto byte : j.get_binary())
6120 {
6121 seed = combine(seed, std::hash<std::uint8_t> {}(byte));
6122 }
6123 return seed;
6124 }
6125
6126 default: // LCOV_EXCL_LINE
6127 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
6128 return 0; // LCOV_EXCL_LINE
6129 }
6130}
6131
6132} // namespace detail
6133NLOHMANN_JSON_NAMESPACE_END
6134
6135// #include <nlohmann/detail/input/binary_reader.hpp>
6136// __ _____ _____ _____
6137// __| | __| | | | JSON for Modern C++
6138// | | |__ | | | | | | version 3.11.3
6139// |_____|_____|_____|_|___| https://github.com/nlohmann/json
6140//
6141// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
6142// SPDX-License-Identifier: MIT
6143
6144
6145
6146#include <algorithm> // generate_n
6147#include <array> // array
6148#include <cmath> // ldexp
6149#include <cstddef> // size_t
6150#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
6151#include <cstdio> // snprintf
6152#include <cstring> // memcpy
6153#include <iterator> // back_inserter
6154#include <limits> // numeric_limits
6155#include <string> // char_traits, string
6156#include <utility> // make_pair, move
6157#include <vector> // vector
6158
6159// #include <nlohmann/detail/exceptions.hpp>
6160
6161// #include <nlohmann/detail/input/input_adapters.hpp>
6162// __ _____ _____ _____
6163// __| | __| | | | JSON for Modern C++
6164// | | |__ | | | | | | version 3.11.3
6165// |_____|_____|_____|_|___| https://github.com/nlohmann/json
6166//
6167// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
6168// SPDX-License-Identifier: MIT
6169
6170
6171
6172#include <array> // array
6173#include <cstddef> // size_t
6174#include <cstring> // strlen
6175#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
6176#include <memory> // shared_ptr, make_shared, addressof
6177#include <numeric> // accumulate
6178#include <string> // string, char_traits
6179#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
6180#include <utility> // pair, declval
6181
6182#ifndef JSON_NO_IO
6183 #include <cstdio> // FILE *
6184 #include <istream> // istream
6185#endif // JSON_NO_IO
6186
6187// #include <nlohmann/detail/iterators/iterator_traits.hpp>
6188
6189// #include <nlohmann/detail/macro_scope.hpp>
6190
6191// #include <nlohmann/detail/meta/type_traits.hpp>
6192
6193
6194NLOHMANN_JSON_NAMESPACE_BEGIN
6195namespace detail
6196{
6197
6199enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata };
6200
6202// input adapters //
6204
6205#ifndef JSON_NO_IO
6211{
6212 public:
6213 using char_type = char;
6214
6215 JSON_HEDLEY_NON_NULL(2)
6216 explicit file_input_adapter(std::FILE* f) noexcept
6217 : m_file(f)
6218 {
6219 JSON_ASSERT(m_file != nullptr);
6220 }
6221
6222 // make class move-only
6223 file_input_adapter(const file_input_adapter&) = delete;
6224 file_input_adapter(file_input_adapter&&) noexcept = default;
6225 file_input_adapter& operator=(const file_input_adapter&) = delete;
6226 file_input_adapter& operator=(file_input_adapter&&) = delete;
6227 ~file_input_adapter() = default;
6228
6229 std::char_traits<char>::int_type get_character() noexcept
6230 {
6231 return std::fgetc(m_file);
6232 }
6233
6234 private:
6236 std::FILE* m_file;
6237};
6238
6249{
6250 public:
6251 using char_type = char;
6252
6254 {
6255 // clear stream flags; we use underlying streambuf I/O, do not
6256 // maintain ifstream flags, except eof
6257 if (is != nullptr)
6258 {
6259 is->clear(is->rdstate() & std::ios::eofbit);
6260 }
6261 }
6262
6263 explicit input_stream_adapter(std::istream& i)
6264 : is(&i), sb(i.rdbuf())
6265 {}
6266
6267 // delete because of pointer members
6269 input_stream_adapter& operator=(input_stream_adapter&) = delete;
6270 input_stream_adapter& operator=(input_stream_adapter&&) = delete;
6271
6273 : is(rhs.is), sb(rhs.sb)
6274 {
6275 rhs.is = nullptr;
6276 rhs.sb = nullptr;
6277 }
6278
6279 // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to
6280 // ensure that std::char_traits<char>::eof() and the character 0xFF do not
6281 // end up as the same value, e.g. 0xFFFFFFFF.
6282 std::char_traits<char>::int_type get_character()
6283 {
6284 auto res = sb->sbumpc();
6285 // set eof manually, as we don't use the istream interface.
6286 if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof()))
6287 {
6288 is->clear(is->rdstate() | std::ios::eofbit);
6289 }
6290 return res;
6291 }
6292
6293 private:
6295 std::istream* is = nullptr;
6296 std::streambuf* sb = nullptr;
6297};
6298#endif // JSON_NO_IO
6299
6300// General-purpose iterator-based adapter. It might not be as fast as
6301// theoretically possible for some containers, but it is extremely versatile.
6302template<typename IteratorType>
6304{
6305 public:
6306 using char_type = typename std::iterator_traits<IteratorType>::value_type;
6307
6308 iterator_input_adapter(IteratorType first, IteratorType last)
6309 : current(std::move(first)), end(std::move(last))
6310 {}
6311
6312 typename char_traits<char_type>::int_type get_character()
6313 {
6314 if (JSON_HEDLEY_LIKELY(current != end))
6315 {
6316 auto result = char_traits<char_type>::to_int_type(*current);
6317 std::advance(current, 1);
6318 return result;
6319 }
6320
6322 }
6323
6324 private:
6325 IteratorType current;
6326 IteratorType end;
6327
6328 template<typename BaseInputAdapter, size_t T>
6329 friend struct wide_string_input_helper;
6330
6331 bool empty() const
6332 {
6333 return current == end;
6334 }
6335};
6336
6337template<typename BaseInputAdapter, size_t T>
6339
6340template<typename BaseInputAdapter>
6341struct wide_string_input_helper<BaseInputAdapter, 4>
6342{
6343 // UTF-32
6344 static void fill_buffer(BaseInputAdapter& input,
6345 std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
6346 size_t& utf8_bytes_index,
6347 size_t& utf8_bytes_filled)
6348 {
6349 utf8_bytes_index = 0;
6350
6351 if (JSON_HEDLEY_UNLIKELY(input.empty()))
6352 {
6353 utf8_bytes[0] = std::char_traits<char>::eof();
6354 utf8_bytes_filled = 1;
6355 }
6356 else
6357 {
6358 // get the current character
6359 const auto wc = input.get_character();
6360
6361 // UTF-32 to UTF-8 encoding
6362 if (wc < 0x80)
6363 {
6364 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
6365 utf8_bytes_filled = 1;
6366 }
6367 else if (wc <= 0x7FF)
6368 {
6369 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u) & 0x1Fu));
6370 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
6371 utf8_bytes_filled = 2;
6372 }
6373 else if (wc <= 0xFFFF)
6374 {
6375 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u) & 0x0Fu));
6376 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
6377 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
6378 utf8_bytes_filled = 3;
6379 }
6380 else if (wc <= 0x10FFFF)
6381 {
6382 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((static_cast<unsigned int>(wc) >> 18u) & 0x07u));
6383 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 12u) & 0x3Fu));
6384 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
6385 utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
6386 utf8_bytes_filled = 4;
6387 }
6388 else
6389 {
6390 // unknown character
6391 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
6392 utf8_bytes_filled = 1;
6393 }
6394 }
6395 }
6396};
6397
6398template<typename BaseInputAdapter>
6399struct wide_string_input_helper<BaseInputAdapter, 2>
6400{
6401 // UTF-16
6402 static void fill_buffer(BaseInputAdapter& input,
6403 std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
6404 size_t& utf8_bytes_index,
6405 size_t& utf8_bytes_filled)
6406 {
6407 utf8_bytes_index = 0;
6408
6409 if (JSON_HEDLEY_UNLIKELY(input.empty()))
6410 {
6411 utf8_bytes[0] = std::char_traits<char>::eof();
6412 utf8_bytes_filled = 1;
6413 }
6414 else
6415 {
6416 // get the current character
6417 const auto wc = input.get_character();
6418
6419 // UTF-16 to UTF-8 encoding
6420 if (wc < 0x80)
6421 {
6422 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
6423 utf8_bytes_filled = 1;
6424 }
6425 else if (wc <= 0x7FF)
6426 {
6427 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u)));
6428 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
6429 utf8_bytes_filled = 2;
6430 }
6431 else if (0xD800 > wc || wc >= 0xE000)
6432 {
6433 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));
6434 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));
6435 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));
6436 utf8_bytes_filled = 3;
6437 }
6438 else
6439 {
6440 if (JSON_HEDLEY_UNLIKELY(!input.empty()))
6441 {
6442 const auto wc2 = static_cast<unsigned int>(input.get_character());
6443 const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
6444 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));
6445 utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));
6446 utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));
6447 utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));
6448 utf8_bytes_filled = 4;
6449 }
6450 else
6451 {
6452 utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
6453 utf8_bytes_filled = 1;
6454 }
6455 }
6456 }
6457 }
6458};
6459
6460// Wraps another input adapter to convert wide character types into individual bytes.
6461template<typename BaseInputAdapter, typename WideCharType>
6463{
6464 public:
6465 using char_type = char;
6466
6467 wide_string_input_adapter(BaseInputAdapter base)
6468 : base_adapter(base) {}
6469
6470 typename std::char_traits<char>::int_type get_character() noexcept
6471 {
6472 // check if buffer needs to be filled
6474 {
6475 fill_buffer<sizeof(WideCharType)>();
6476
6477 JSON_ASSERT(utf8_bytes_filled > 0);
6478 JSON_ASSERT(utf8_bytes_index == 0);
6479 }
6480
6481 // use buffer
6482 JSON_ASSERT(utf8_bytes_filled > 0);
6483 JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);
6484 return utf8_bytes[utf8_bytes_index++];
6485 }
6486
6487 private:
6488 BaseInputAdapter base_adapter;
6489
6490 template<size_t T>
6491 void fill_buffer()
6492 {
6494 }
6495
6497 std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
6498
6500 std::size_t utf8_bytes_index = 0;
6502 std::size_t utf8_bytes_filled = 0;
6503};
6504
6505template<typename IteratorType, typename Enable = void>
6507{
6508 using iterator_type = IteratorType;
6509 using char_type = typename std::iterator_traits<iterator_type>::value_type;
6510 using adapter_type = iterator_input_adapter<iterator_type>;
6511
6512 static adapter_type create(IteratorType first, IteratorType last)
6513 {
6514 return adapter_type(std::move(first), std::move(last));
6515 }
6516};
6517
6518template<typename T>
6520{
6521 using value_type = typename std::iterator_traits<T>::value_type;
6522 enum
6523 {
6524 value = sizeof(value_type) > 1
6525 };
6526};
6527
6528template<typename IteratorType>
6529struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>
6530{
6531 using iterator_type = IteratorType;
6532 using char_type = typename std::iterator_traits<iterator_type>::value_type;
6533 using base_adapter_type = iterator_input_adapter<iterator_type>;
6535
6536 static adapter_type create(IteratorType first, IteratorType last)
6537 {
6538 return adapter_type(base_adapter_type(std::move(first), std::move(last)));
6539 }
6540};
6541
6542// General purpose iterator-based input
6543template<typename IteratorType>
6544typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)
6545{
6547 return factory_type::create(first, last);
6548}
6549
6550// Convenience shorthand from container to iterator
6551// Enables ADL on begin(container) and end(container)
6552// Encloses the using declarations in namespace for not to leak them to outside scope
6553
6554namespace container_input_adapter_factory_impl
6555{
6556
6557using std::begin;
6558using std::end;
6559
6560template<typename ContainerType, typename Enable = void>
6562
6563template<typename ContainerType>
6565 void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>>
6566 {
6567 using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
6568
6569 static adapter_type create(const ContainerType& container)
6570{
6571 return input_adapter(begin(container), end(container));
6572}
6573 };
6574
6575} // namespace container_input_adapter_factory_impl
6576
6577template<typename ContainerType>
6579{
6581}
6582
6583#ifndef JSON_NO_IO
6584// Special cases with fast paths
6585inline file_input_adapter input_adapter(std::FILE* file)
6586{
6587 return file_input_adapter(file);
6588}
6589
6590inline input_stream_adapter input_adapter(std::istream& stream)
6591{
6592 return input_stream_adapter(stream);
6593}
6594
6595inline input_stream_adapter input_adapter(std::istream&& stream)
6596{
6597 return input_stream_adapter(stream);
6598}
6599#endif // JSON_NO_IO
6600
6601using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));
6602
6603// Null-delimited strings, and the like.
6604template < typename CharT,
6605 typename std::enable_if <
6606 std::is_pointer<CharT>::value&&
6607 !std::is_array<CharT>::value&&
6608 std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
6609 sizeof(typename std::remove_pointer<CharT>::type) == 1,
6610 int >::type = 0 >
6611contiguous_bytes_input_adapter input_adapter(CharT b)
6612{
6613 auto length = std::strlen(reinterpret_cast<const char*>(b));
6614 const auto* ptr = reinterpret_cast<const char*>(b);
6615 return input_adapter(ptr, ptr + length);
6616}
6617
6618template<typename T, std::size_t N>
6619auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
6620{
6621 return input_adapter(array, array + N);
6622}
6623
6624// This class only handles inputs of input_buffer_adapter type.
6625// It's required so that expressions like {ptr, len} can be implicitly cast
6626// to the correct adapter.
6628{
6629 public:
6630 template < typename CharT,
6631 typename std::enable_if <
6632 std::is_pointer<CharT>::value&&
6633 std::is_integral<typename std::remove_pointer<CharT>::type>::value&&
6634 sizeof(typename std::remove_pointer<CharT>::type) == 1,
6635 int >::type = 0 >
6636 span_input_adapter(CharT b, std::size_t l)
6637 : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {}
6638
6639 template<class IteratorType,
6640 typename std::enable_if<
6641 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
6642 int>::type = 0>
6643 span_input_adapter(IteratorType first, IteratorType last)
6644 : ia(input_adapter(first, last)) {}
6645
6646 contiguous_bytes_input_adapter&& get()
6647 {
6648 return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
6649 }
6650
6651 private:
6652 contiguous_bytes_input_adapter ia;
6653};
6654
6655} // namespace detail
6656NLOHMANN_JSON_NAMESPACE_END
6657
6658// #include <nlohmann/detail/input/json_sax.hpp>
6659// __ _____ _____ _____
6660// __| | __| | | | JSON for Modern C++
6661// | | |__ | | | | | | version 3.11.3
6662// |_____|_____|_____|_|___| https://github.com/nlohmann/json
6663//
6664// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
6665// SPDX-License-Identifier: MIT
6666
6667
6668
6669#include <cstddef>
6670#include <string> // string
6671#include <utility> // move
6672#include <vector> // vector
6673
6674// #include <nlohmann/detail/exceptions.hpp>
6675
6676// #include <nlohmann/detail/macro_scope.hpp>
6677
6678// #include <nlohmann/detail/string_concat.hpp>
6679
6680
6681NLOHMANN_JSON_NAMESPACE_BEGIN
6682
6691template<typename BasicJsonType>
6693{
6694 using number_integer_t = typename BasicJsonType::number_integer_t;
6695 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
6696 using number_float_t = typename BasicJsonType::number_float_t;
6697 using string_t = typename BasicJsonType::string_t;
6698 using binary_t = typename BasicJsonType::binary_t;
6699
6704 virtual bool null() = 0;
6705
6711 virtual bool boolean(bool val) = 0;
6712
6718 virtual bool number_integer(number_integer_t val) = 0;
6719
6725 virtual bool number_unsigned(number_unsigned_t val) = 0;
6726
6733 virtual bool number_float(number_float_t val, const string_t& s) = 0;
6734
6741 virtual bool string(string_t& val) = 0;
6742
6749 virtual bool binary(binary_t& val) = 0;
6750
6757 virtual bool start_object(std::size_t elements) = 0;
6758
6765 virtual bool key(string_t& val) = 0;
6766
6771 virtual bool end_object() = 0;
6772
6779 virtual bool start_array(std::size_t elements) = 0;
6780
6785 virtual bool end_array() = 0;
6786
6794 virtual bool parse_error(std::size_t position,
6795 const std::string& last_token,
6796 const detail::exception& ex) = 0;
6797
6798 json_sax() = default;
6799 json_sax(const json_sax&) = default;
6800 json_sax(json_sax&&) noexcept = default;
6801 json_sax& operator=(const json_sax&) = default;
6802 json_sax& operator=(json_sax&&) noexcept = default;
6803 virtual ~json_sax() = default;
6804};
6805
6806namespace detail
6807{
6821template<typename BasicJsonType>
6823{
6824 public:
6825 using number_integer_t = typename BasicJsonType::number_integer_t;
6826 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
6827 using number_float_t = typename BasicJsonType::number_float_t;
6828 using string_t = typename BasicJsonType::string_t;
6829 using binary_t = typename BasicJsonType::binary_t;
6830
6836 explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
6837 : root(r), allow_exceptions(allow_exceptions_)
6838 {}
6839
6840 // make class move-only
6842 json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
6843 json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
6844 json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
6845 ~json_sax_dom_parser() = default;
6846
6847 bool null()
6848 {
6849 handle_value(nullptr);
6850 return true;
6851 }
6852
6853 bool boolean(bool val)
6854 {
6855 handle_value(val);
6856 return true;
6857 }
6858
6859 bool number_integer(number_integer_t val)
6860 {
6861 handle_value(val);
6862 return true;
6863 }
6864
6865 bool number_unsigned(number_unsigned_t val)
6866 {
6867 handle_value(val);
6868 return true;
6869 }
6870
6871 bool number_float(number_float_t val, const string_t& /*unused*/)
6872 {
6873 handle_value(val);
6874 return true;
6875 }
6876
6877 bool string(string_t& val)
6878 {
6879 handle_value(val);
6880 return true;
6881 }
6882
6883 bool binary(binary_t& val)
6884 {
6885 handle_value(std::move(val));
6886 return true;
6887 }
6888
6889 bool start_object(std::size_t len)
6890 {
6891 ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
6892
6893 if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
6894 {
6895 JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
6896 }
6897
6898 return true;
6899 }
6900
6901 bool key(string_t& val)
6902 {
6903 JSON_ASSERT(!ref_stack.empty());
6904 JSON_ASSERT(ref_stack.back()->is_object());
6905
6906 // add null at given key and store the reference for later
6907 object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val));
6908 return true;
6909 }
6910
6911 bool end_object()
6912 {
6913 JSON_ASSERT(!ref_stack.empty());
6914 JSON_ASSERT(ref_stack.back()->is_object());
6915
6916 ref_stack.back()->set_parents();
6917 ref_stack.pop_back();
6918 return true;
6919 }
6920
6921 bool start_array(std::size_t len)
6922 {
6923 ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
6924
6925 if (JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
6926 {
6927 JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
6928 }
6929
6930 return true;
6931 }
6932
6933 bool end_array()
6934 {
6935 JSON_ASSERT(!ref_stack.empty());
6936 JSON_ASSERT(ref_stack.back()->is_array());
6937
6938 ref_stack.back()->set_parents();
6939 ref_stack.pop_back();
6940 return true;
6941 }
6942
6943 template<class Exception>
6944 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
6945 const Exception& ex)
6946 {
6947 errored = true;
6948 static_cast<void>(ex);
6949 if (allow_exceptions)
6950 {
6951 JSON_THROW(ex);
6952 }
6953 return false;
6954 }
6955
6956 constexpr bool is_errored() const
6957 {
6958 return errored;
6959 }
6960
6961 private:
6968 template<typename Value>
6969 JSON_HEDLEY_RETURNS_NON_NULL
6970 BasicJsonType* handle_value(Value&& v)
6971 {
6972 if (ref_stack.empty())
6973 {
6974 root = BasicJsonType(std::forward<Value>(v));
6975 return &root;
6976 }
6977
6978 JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
6979
6980 if (ref_stack.back()->is_array())
6981 {
6982 ref_stack.back()->m_data.m_value.array->emplace_back(std::forward<Value>(v));
6983 return &(ref_stack.back()->m_data.m_value.array->back());
6984 }
6985
6986 JSON_ASSERT(ref_stack.back()->is_object());
6987 JSON_ASSERT(object_element);
6988 *object_element = BasicJsonType(std::forward<Value>(v));
6989 return object_element;
6990 }
6991
6993 BasicJsonType& root;
6995 std::vector<BasicJsonType*> ref_stack {};
6997 BasicJsonType* object_element = nullptr;
6999 bool errored = false;
7001 const bool allow_exceptions = true;
7002};
7003
7004template<typename BasicJsonType>
7006{
7007 public:
7008 using number_integer_t = typename BasicJsonType::number_integer_t;
7009 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
7010 using number_float_t = typename BasicJsonType::number_float_t;
7011 using string_t = typename BasicJsonType::string_t;
7012 using binary_t = typename BasicJsonType::binary_t;
7013 using parser_callback_t = typename BasicJsonType::parser_callback_t;
7014 using parse_event_t = typename BasicJsonType::parse_event_t;
7015
7016 json_sax_dom_callback_parser(BasicJsonType& r,
7017 const parser_callback_t cb,
7018 const bool allow_exceptions_ = true)
7019 : root(r), callback(cb), allow_exceptions(allow_exceptions_)
7020 {
7021 keep_stack.push_back(true);
7022 }
7023
7024 // make class move-only
7026 json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
7028 json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
7030
7031 bool null()
7032 {
7033 handle_value(nullptr);
7034 return true;
7035 }
7036
7037 bool boolean(bool val)
7038 {
7039 handle_value(val);
7040 return true;
7041 }
7042
7043 bool number_integer(number_integer_t val)
7044 {
7045 handle_value(val);
7046 return true;
7047 }
7048
7049 bool number_unsigned(number_unsigned_t val)
7050 {
7051 handle_value(val);
7052 return true;
7053 }
7054
7055 bool number_float(number_float_t val, const string_t& /*unused*/)
7056 {
7057 handle_value(val);
7058 return true;
7059 }
7060
7061 bool string(string_t& val)
7062 {
7063 handle_value(val);
7064 return true;
7065 }
7066
7067 bool binary(binary_t& val)
7068 {
7069 handle_value(std::move(val));
7070 return true;
7071 }
7072
7073 bool start_object(std::size_t len)
7074 {
7075 // check callback for object start
7076 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
7077 keep_stack.push_back(keep);
7078
7079 auto val = handle_value(BasicJsonType::value_t::object, true);
7080 ref_stack.push_back(val.second);
7081
7082 // check object limit
7083 if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
7084 {
7085 JSON_THROW(out_of_range::create(408, concat("excessive object size: ", std::to_string(len)), ref_stack.back()));
7086 }
7087
7088 return true;
7089 }
7090
7091 bool key(string_t& val)
7092 {
7093 BasicJsonType k = BasicJsonType(val);
7094
7095 // check callback for key
7096 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
7097 key_keep_stack.push_back(keep);
7098
7099 // add discarded value at given key and store the reference for later
7100 if (keep && ref_stack.back())
7101 {
7102 object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded);
7103 }
7104
7105 return true;
7106 }
7107
7108 bool end_object()
7109 {
7110 if (ref_stack.back())
7111 {
7112 if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
7113 {
7114 // discard object
7115 *ref_stack.back() = discarded;
7116 }
7117 else
7118 {
7119 ref_stack.back()->set_parents();
7120 }
7121 }
7122
7123 JSON_ASSERT(!ref_stack.empty());
7124 JSON_ASSERT(!keep_stack.empty());
7125 ref_stack.pop_back();
7126 keep_stack.pop_back();
7127
7128 if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
7129 {
7130 // remove discarded value
7131 for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
7132 {
7133 if (it->is_discarded())
7134 {
7135 ref_stack.back()->erase(it);
7136 break;
7137 }
7138 }
7139 }
7140
7141 return true;
7142 }
7143
7144 bool start_array(std::size_t len)
7145 {
7146 const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
7147 keep_stack.push_back(keep);
7148
7149 auto val = handle_value(BasicJsonType::value_t::array, true);
7150 ref_stack.push_back(val.second);
7151
7152 // check array limit
7153 if (ref_stack.back() && JSON_HEDLEY_UNLIKELY(len != static_cast<std::size_t>(-1) && len > ref_stack.back()->max_size()))
7154 {
7155 JSON_THROW(out_of_range::create(408, concat("excessive array size: ", std::to_string(len)), ref_stack.back()));
7156 }
7157
7158 return true;
7159 }
7160
7161 bool end_array()
7162 {
7163 bool keep = true;
7164
7165 if (ref_stack.back())
7166 {
7167 keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
7168 if (keep)
7169 {
7170 ref_stack.back()->set_parents();
7171 }
7172 else
7173 {
7174 // discard array
7175 *ref_stack.back() = discarded;
7176 }
7177 }
7178
7179 JSON_ASSERT(!ref_stack.empty());
7180 JSON_ASSERT(!keep_stack.empty());
7181 ref_stack.pop_back();
7182 keep_stack.pop_back();
7183
7184 // remove discarded value
7185 if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())
7186 {
7187 ref_stack.back()->m_data.m_value.array->pop_back();
7188 }
7189
7190 return true;
7191 }
7192
7193 template<class Exception>
7194 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,
7195 const Exception& ex)
7196 {
7197 errored = true;
7198 static_cast<void>(ex);
7199 if (allow_exceptions)
7200 {
7201 JSON_THROW(ex);
7202 }
7203 return false;
7204 }
7205
7206 constexpr bool is_errored() const
7207 {
7208 return errored;
7209 }
7210
7211 private:
7227 template<typename Value>
7228 std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
7229 {
7230 JSON_ASSERT(!keep_stack.empty());
7231
7232 // do not handle this value if we know it would be added to a discarded
7233 // container
7234 if (!keep_stack.back())
7235 {
7236 return {false, nullptr};
7237 }
7238
7239 // create value
7240 auto value = BasicJsonType(std::forward<Value>(v));
7241
7242 // check callback
7243 const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
7244
7245 // do not handle this value if we just learnt it shall be discarded
7246 if (!keep)
7247 {
7248 return {false, nullptr};
7249 }
7250
7251 if (ref_stack.empty())
7252 {
7253 root = std::move(value);
7254 return {true, & root};
7255 }
7256
7257 // skip this value if we already decided to skip the parent
7258 // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
7259 if (!ref_stack.back())
7260 {
7261 return {false, nullptr};
7262 }
7263
7264 // we now only expect arrays and objects
7265 JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());
7266
7267 // array
7268 if (ref_stack.back()->is_array())
7269 {
7270 ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value));
7271 return {true, & (ref_stack.back()->m_data.m_value.array->back())};
7272 }
7273
7274 // object
7275 JSON_ASSERT(ref_stack.back()->is_object());
7276 // check if we should store an element for the current key
7277 JSON_ASSERT(!key_keep_stack.empty());
7278 const bool store_element = key_keep_stack.back();
7279 key_keep_stack.pop_back();
7280
7281 if (!store_element)
7282 {
7283 return {false, nullptr};
7284 }
7285
7286 JSON_ASSERT(object_element);
7287 *object_element = std::move(value);
7288 return {true, object_element};
7289 }
7290
7292 BasicJsonType& root;
7294 std::vector<BasicJsonType*> ref_stack {};
7296 std::vector<bool> keep_stack {};
7298 std::vector<bool> key_keep_stack {};
7300 BasicJsonType* object_element = nullptr;
7302 bool errored = false;
7304 const parser_callback_t callback = nullptr;
7306 const bool allow_exceptions = true;
7308 BasicJsonType discarded = BasicJsonType::value_t::discarded;
7309};
7310
7311template<typename BasicJsonType>
7313{
7314 public:
7315 using number_integer_t = typename BasicJsonType::number_integer_t;
7316 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
7317 using number_float_t = typename BasicJsonType::number_float_t;
7318 using string_t = typename BasicJsonType::string_t;
7319 using binary_t = typename BasicJsonType::binary_t;
7320
7321 bool null()
7322 {
7323 return true;
7324 }
7325
7326 bool boolean(bool /*unused*/)
7327 {
7328 return true;
7329 }
7330
7331 bool number_integer(number_integer_t /*unused*/)
7332 {
7333 return true;
7334 }
7335
7336 bool number_unsigned(number_unsigned_t /*unused*/)
7337 {
7338 return true;
7339 }
7340
7341 bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)
7342 {
7343 return true;
7344 }
7345
7346 bool string(string_t& /*unused*/)
7347 {
7348 return true;
7349 }
7350
7351 bool binary(binary_t& /*unused*/)
7352 {
7353 return true;
7354 }
7355
7356 bool start_object(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
7357 {
7358 return true;
7359 }
7360
7361 bool key(string_t& /*unused*/)
7362 {
7363 return true;
7364 }
7365
7366 bool end_object()
7367 {
7368 return true;
7369 }
7370
7371 bool start_array(std::size_t /*unused*/ = static_cast<std::size_t>(-1))
7372 {
7373 return true;
7374 }
7375
7376 bool end_array()
7377 {
7378 return true;
7379 }
7380
7381 bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)
7382 {
7383 return false;
7384 }
7385};
7386
7387} // namespace detail
7388NLOHMANN_JSON_NAMESPACE_END
7389
7390// #include <nlohmann/detail/input/lexer.hpp>
7391// __ _____ _____ _____
7392// __| | __| | | | JSON for Modern C++
7393// | | |__ | | | | | | version 3.11.3
7394// |_____|_____|_____|_|___| https://github.com/nlohmann/json
7395//
7396// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
7397// SPDX-License-Identifier: MIT
7398
7399
7400
7401#include <array> // array
7402#include <clocale> // localeconv
7403#include <cstddef> // size_t
7404#include <cstdio> // snprintf
7405#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
7406#include <initializer_list> // initializer_list
7407#include <string> // char_traits, string
7408#include <utility> // move
7409#include <vector> // vector
7410
7411// #include <nlohmann/detail/input/input_adapters.hpp>
7412
7413// #include <nlohmann/detail/input/position_t.hpp>
7414
7415// #include <nlohmann/detail/macro_scope.hpp>
7416
7417// #include <nlohmann/detail/meta/type_traits.hpp>
7418
7419
7420NLOHMANN_JSON_NAMESPACE_BEGIN
7421namespace detail
7422{
7423
7425// lexer //
7427
7428template<typename BasicJsonType>
7430{
7431 public:
7433 enum class token_type
7434 {
7435 uninitialized,
7436 literal_true,
7437 literal_false,
7438 literal_null,
7439 value_string,
7440 value_unsigned,
7441 value_integer,
7442 value_float,
7443 begin_array,
7444 begin_object,
7445 end_array,
7446 end_object,
7447 name_separator,
7448 value_separator,
7449 parse_error,
7450 end_of_input,
7451 literal_or_value
7452 };
7453
7455 JSON_HEDLEY_RETURNS_NON_NULL
7456 JSON_HEDLEY_CONST
7457 static const char* token_type_name(const token_type t) noexcept
7458 {
7459 switch (t)
7460 {
7461 case token_type::uninitialized:
7462 return "<uninitialized>";
7463 case token_type::literal_true:
7464 return "true literal";
7465 case token_type::literal_false:
7466 return "false literal";
7467 case token_type::literal_null:
7468 return "null literal";
7469 case token_type::value_string:
7470 return "string literal";
7471 case token_type::value_unsigned:
7472 case token_type::value_integer:
7473 case token_type::value_float:
7474 return "number literal";
7475 case token_type::begin_array:
7476 return "'['";
7477 case token_type::begin_object:
7478 return "'{'";
7479 case token_type::end_array:
7480 return "']'";
7481 case token_type::end_object:
7482 return "'}'";
7483 case token_type::name_separator:
7484 return "':'";
7485 case token_type::value_separator:
7486 return "','";
7487 case token_type::parse_error:
7488 return "<parse error>";
7489 case token_type::end_of_input:
7490 return "end of input";
7491 case token_type::literal_or_value:
7492 return "'[', '{', or a literal";
7493 // LCOV_EXCL_START
7494 default: // catch non-enum values
7495 return "unknown token";
7496 // LCOV_EXCL_STOP
7497 }
7498 }
7499};
7505template<typename BasicJsonType, typename InputAdapterType>
7506class lexer : public lexer_base<BasicJsonType>
7507{
7508 using number_integer_t = typename BasicJsonType::number_integer_t;
7509 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
7510 using number_float_t = typename BasicJsonType::number_float_t;
7511 using string_t = typename BasicJsonType::string_t;
7512 using char_type = typename InputAdapterType::char_type;
7513 using char_int_type = typename char_traits<char_type>::int_type;
7514
7515 public:
7516 using token_type = typename lexer_base<BasicJsonType>::token_type;
7517
7518 explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept
7519 : ia(std::move(adapter))
7520 , ignore_comments(ignore_comments_)
7521 , decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
7522 {}
7523
7524 // delete because of pointer members
7525 lexer(const lexer&) = delete;
7526 lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
7527 lexer& operator=(lexer&) = delete;
7528 lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
7529 ~lexer() = default;
7530
7531 private:
7533 // locales
7535
7537 JSON_HEDLEY_PURE
7538 static char get_decimal_point() noexcept
7539 {
7540 const auto* loc = localeconv();
7541 JSON_ASSERT(loc != nullptr);
7542 return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
7543 }
7544
7546 // scan functions
7548
7565 {
7566 // this function only makes sense after reading `\u`
7567 JSON_ASSERT(current == 'u');
7568 int codepoint = 0;
7569
7570 const auto factors = { 12u, 8u, 4u, 0u };
7571 for (const auto factor : factors)
7572 {
7573 get();
7574
7575 if (current >= '0' && current <= '9')
7576 {
7577 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);
7578 }
7579 else if (current >= 'A' && current <= 'F')
7580 {
7581 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);
7582 }
7583 else if (current >= 'a' && current <= 'f')
7584 {
7585 codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);
7586 }
7587 else
7588 {
7589 return -1;
7590 }
7591 }
7592
7593 JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF);
7594 return codepoint;
7595 }
7596
7612 bool next_byte_in_range(std::initializer_list<char_int_type> ranges)
7613 {
7614 JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);
7615 add(current);
7616
7617 for (auto range = ranges.begin(); range != ranges.end(); ++range)
7618 {
7619 get();
7620 if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) // NOLINT(bugprone-inc-dec-in-conditions)
7621 {
7622 add(current);
7623 }
7624 else
7625 {
7626 error_message = "invalid string: ill-formed UTF-8 byte";
7627 return false;
7628 }
7629 }
7630
7631 return true;
7632 }
7633
7649 token_type scan_string()
7650 {
7651 // reset token_buffer (ignore opening quote)
7652 reset();
7653
7654 // we entered the function by reading an open quote
7655 JSON_ASSERT(current == '\"');
7656
7657 while (true)
7658 {
7659 // get next character
7660 switch (get())
7661 {
7662 // end of file while parsing string
7664 {
7665 error_message = "invalid string: missing closing quote";
7666 return token_type::parse_error;
7667 }
7668
7669 // closing quote
7670 case '\"':
7671 {
7672 return token_type::value_string;
7673 }
7674
7675 // escapes
7676 case '\\':
7677 {
7678 switch (get())
7679 {
7680 // quotation mark
7681 case '\"':
7682 add('\"');
7683 break;
7684 // reverse solidus
7685 case '\\':
7686 add('\\');
7687 break;
7688 // solidus
7689 case '/':
7690 add('/');
7691 break;
7692 // backspace
7693 case 'b':
7694 add('\b');
7695 break;
7696 // form feed
7697 case 'f':
7698 add('\f');
7699 break;
7700 // line feed
7701 case 'n':
7702 add('\n');
7703 break;
7704 // carriage return
7705 case 'r':
7706 add('\r');
7707 break;
7708 // tab
7709 case 't':
7710 add('\t');
7711 break;
7712
7713 // unicode escapes
7714 case 'u':
7715 {
7716 const int codepoint1 = get_codepoint();
7717 int codepoint = codepoint1; // start with codepoint1
7718
7719 if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1))
7720 {
7721 error_message = "invalid string: '\\u' must be followed by 4 hex digits";
7722 return token_type::parse_error;
7723 }
7724
7725 // check if code point is a high surrogate
7726 if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF)
7727 {
7728 // expect next \uxxxx entry
7729 if (JSON_HEDLEY_LIKELY(get() == '\\' && get() == 'u'))
7730 {
7731 const int codepoint2 = get_codepoint();
7732
7733 if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1))
7734 {
7735 error_message = "invalid string: '\\u' must be followed by 4 hex digits";
7736 return token_type::parse_error;
7737 }
7738
7739 // check if codepoint2 is a low surrogate
7740 if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF))
7741 {
7742 // overwrite codepoint
7743 codepoint = static_cast<int>(
7744 // high surrogate occupies the most significant 22 bits
7745 (static_cast<unsigned int>(codepoint1) << 10u)
7746 // low surrogate occupies the least significant 15 bits
7747 + static_cast<unsigned int>(codepoint2)
7748 // there is still the 0xD800, 0xDC00 and 0x10000 noise
7749 // in the result, so we have to subtract with:
7750 // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
7751 - 0x35FDC00u);
7752 }
7753 else
7754 {
7755 error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF";
7756 return token_type::parse_error;
7757 }
7758 }
7759 else
7760 {
7761 error_message = "invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF";
7762 return token_type::parse_error;
7763 }
7764 }
7765 else
7766 {
7767 if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF))
7768 {
7769 error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF";
7770 return token_type::parse_error;
7771 }
7772 }
7773
7774 // result of the above calculation yields a proper codepoint
7775 JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF);
7776
7777 // translate codepoint into bytes
7778 if (codepoint < 0x80)
7779 {
7780 // 1-byte characters: 0xxxxxxx (ASCII)
7781 add(static_cast<char_int_type>(codepoint));
7782 }
7783 else if (codepoint <= 0x7FF)
7784 {
7785 // 2-byte characters: 110xxxxx 10xxxxxx
7786 add(static_cast<char_int_type>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));
7787 add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
7788 }
7789 else if (codepoint <= 0xFFFF)
7790 {
7791 // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
7792 add(static_cast<char_int_type>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));
7793 add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
7794 add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
7795 }
7796 else
7797 {
7798 // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
7799 add(static_cast<char_int_type>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));
7800 add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));
7801 add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
7802 add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
7803 }
7804
7805 break;
7806 }
7807
7808 // other characters after escape
7809 default:
7810 error_message = "invalid string: forbidden character after backslash";
7811 return token_type::parse_error;
7812 }
7813
7814 break;
7815 }
7816
7817 // invalid control characters
7818 case 0x00:
7819 {
7820 error_message = "invalid string: control character U+0000 (NUL) must be escaped to \\u0000";
7821 return token_type::parse_error;
7822 }
7823
7824 case 0x01:
7825 {
7826 error_message = "invalid string: control character U+0001 (SOH) must be escaped to \\u0001";
7827 return token_type::parse_error;
7828 }
7829
7830 case 0x02:
7831 {
7832 error_message = "invalid string: control character U+0002 (STX) must be escaped to \\u0002";
7833 return token_type::parse_error;
7834 }
7835
7836 case 0x03:
7837 {
7838 error_message = "invalid string: control character U+0003 (ETX) must be escaped to \\u0003";
7839 return token_type::parse_error;
7840 }
7841
7842 case 0x04:
7843 {
7844 error_message = "invalid string: control character U+0004 (EOT) must be escaped to \\u0004";
7845 return token_type::parse_error;
7846 }
7847
7848 case 0x05:
7849 {
7850 error_message = "invalid string: control character U+0005 (ENQ) must be escaped to \\u0005";
7851 return token_type::parse_error;
7852 }
7853
7854 case 0x06:
7855 {
7856 error_message = "invalid string: control character U+0006 (ACK) must be escaped to \\u0006";
7857 return token_type::parse_error;
7858 }
7859
7860 case 0x07:
7861 {
7862 error_message = "invalid string: control character U+0007 (BEL) must be escaped to \\u0007";
7863 return token_type::parse_error;
7864 }
7865
7866 case 0x08:
7867 {
7868 error_message = "invalid string: control character U+0008 (BS) must be escaped to \\u0008 or \\b";
7869 return token_type::parse_error;
7870 }
7871
7872 case 0x09:
7873 {
7874 error_message = "invalid string: control character U+0009 (HT) must be escaped to \\u0009 or \\t";
7875 return token_type::parse_error;
7876 }
7877
7878 case 0x0A:
7879 {
7880 error_message = "invalid string: control character U+000A (LF) must be escaped to \\u000A or \\n";
7881 return token_type::parse_error;
7882 }
7883
7884 case 0x0B:
7885 {
7886 error_message = "invalid string: control character U+000B (VT) must be escaped to \\u000B";
7887 return token_type::parse_error;
7888 }
7889
7890 case 0x0C:
7891 {
7892 error_message = "invalid string: control character U+000C (FF) must be escaped to \\u000C or \\f";
7893 return token_type::parse_error;
7894 }
7895
7896 case 0x0D:
7897 {
7898 error_message = "invalid string: control character U+000D (CR) must be escaped to \\u000D or \\r";
7899 return token_type::parse_error;
7900 }
7901
7902 case 0x0E:
7903 {
7904 error_message = "invalid string: control character U+000E (SO) must be escaped to \\u000E";
7905 return token_type::parse_error;
7906 }
7907
7908 case 0x0F:
7909 {
7910 error_message = "invalid string: control character U+000F (SI) must be escaped to \\u000F";
7911 return token_type::parse_error;
7912 }
7913
7914 case 0x10:
7915 {
7916 error_message = "invalid string: control character U+0010 (DLE) must be escaped to \\u0010";
7917 return token_type::parse_error;
7918 }
7919
7920 case 0x11:
7921 {
7922 error_message = "invalid string: control character U+0011 (DC1) must be escaped to \\u0011";
7923 return token_type::parse_error;
7924 }
7925
7926 case 0x12:
7927 {
7928 error_message = "invalid string: control character U+0012 (DC2) must be escaped to \\u0012";
7929 return token_type::parse_error;
7930 }
7931
7932 case 0x13:
7933 {
7934 error_message = "invalid string: control character U+0013 (DC3) must be escaped to \\u0013";
7935 return token_type::parse_error;
7936 }
7937
7938 case 0x14:
7939 {
7940 error_message = "invalid string: control character U+0014 (DC4) must be escaped to \\u0014";
7941 return token_type::parse_error;
7942 }
7943
7944 case 0x15:
7945 {
7946 error_message = "invalid string: control character U+0015 (NAK) must be escaped to \\u0015";
7947 return token_type::parse_error;
7948 }
7949
7950 case 0x16:
7951 {
7952 error_message = "invalid string: control character U+0016 (SYN) must be escaped to \\u0016";
7953 return token_type::parse_error;
7954 }
7955
7956 case 0x17:
7957 {
7958 error_message = "invalid string: control character U+0017 (ETB) must be escaped to \\u0017";
7959 return token_type::parse_error;
7960 }
7961
7962 case 0x18:
7963 {
7964 error_message = "invalid string: control character U+0018 (CAN) must be escaped to \\u0018";
7965 return token_type::parse_error;
7966 }
7967
7968 case 0x19:
7969 {
7970 error_message = "invalid string: control character U+0019 (EM) must be escaped to \\u0019";
7971 return token_type::parse_error;
7972 }
7973
7974 case 0x1A:
7975 {
7976 error_message = "invalid string: control character U+001A (SUB) must be escaped to \\u001A";
7977 return token_type::parse_error;
7978 }
7979
7980 case 0x1B:
7981 {
7982 error_message = "invalid string: control character U+001B (ESC) must be escaped to \\u001B";
7983 return token_type::parse_error;
7984 }
7985
7986 case 0x1C:
7987 {
7988 error_message = "invalid string: control character U+001C (FS) must be escaped to \\u001C";
7989 return token_type::parse_error;
7990 }
7991
7992 case 0x1D:
7993 {
7994 error_message = "invalid string: control character U+001D (GS) must be escaped to \\u001D";
7995 return token_type::parse_error;
7996 }
7997
7998 case 0x1E:
7999 {
8000 error_message = "invalid string: control character U+001E (RS) must be escaped to \\u001E";
8001 return token_type::parse_error;
8002 }
8003
8004 case 0x1F:
8005 {
8006 error_message = "invalid string: control character U+001F (US) must be escaped to \\u001F";
8007 return token_type::parse_error;
8008 }
8009
8010 // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))
8011 case 0x20:
8012 case 0x21:
8013 case 0x23:
8014 case 0x24:
8015 case 0x25:
8016 case 0x26:
8017 case 0x27:
8018 case 0x28:
8019 case 0x29:
8020 case 0x2A:
8021 case 0x2B:
8022 case 0x2C:
8023 case 0x2D:
8024 case 0x2E:
8025 case 0x2F:
8026 case 0x30:
8027 case 0x31:
8028 case 0x32:
8029 case 0x33:
8030 case 0x34:
8031 case 0x35:
8032 case 0x36:
8033 case 0x37:
8034 case 0x38:
8035 case 0x39:
8036 case 0x3A:
8037 case 0x3B:
8038 case 0x3C:
8039 case 0x3D:
8040 case 0x3E:
8041 case 0x3F:
8042 case 0x40:
8043 case 0x41:
8044 case 0x42:
8045 case 0x43:
8046 case 0x44:
8047 case 0x45:
8048 case 0x46:
8049 case 0x47:
8050 case 0x48:
8051 case 0x49:
8052 case 0x4A:
8053 case 0x4B:
8054 case 0x4C:
8055 case 0x4D:
8056 case 0x4E:
8057 case 0x4F:
8058 case 0x50:
8059 case 0x51:
8060 case 0x52:
8061 case 0x53:
8062 case 0x54:
8063 case 0x55:
8064 case 0x56:
8065 case 0x57:
8066 case 0x58:
8067 case 0x59:
8068 case 0x5A:
8069 case 0x5B:
8070 case 0x5D:
8071 case 0x5E:
8072 case 0x5F:
8073 case 0x60:
8074 case 0x61:
8075 case 0x62:
8076 case 0x63:
8077 case 0x64:
8078 case 0x65:
8079 case 0x66:
8080 case 0x67:
8081 case 0x68:
8082 case 0x69:
8083 case 0x6A:
8084 case 0x6B:
8085 case 0x6C:
8086 case 0x6D:
8087 case 0x6E:
8088 case 0x6F:
8089 case 0x70:
8090 case 0x71:
8091 case 0x72:
8092 case 0x73:
8093 case 0x74:
8094 case 0x75:
8095 case 0x76:
8096 case 0x77:
8097 case 0x78:
8098 case 0x79:
8099 case 0x7A:
8100 case 0x7B:
8101 case 0x7C:
8102 case 0x7D:
8103 case 0x7E:
8104 case 0x7F:
8105 {
8106 add(current);
8107 break;
8108 }
8109
8110 // U+0080..U+07FF: bytes C2..DF 80..BF
8111 case 0xC2:
8112 case 0xC3:
8113 case 0xC4:
8114 case 0xC5:
8115 case 0xC6:
8116 case 0xC7:
8117 case 0xC8:
8118 case 0xC9:
8119 case 0xCA:
8120 case 0xCB:
8121 case 0xCC:
8122 case 0xCD:
8123 case 0xCE:
8124 case 0xCF:
8125 case 0xD0:
8126 case 0xD1:
8127 case 0xD2:
8128 case 0xD3:
8129 case 0xD4:
8130 case 0xD5:
8131 case 0xD6:
8132 case 0xD7:
8133 case 0xD8:
8134 case 0xD9:
8135 case 0xDA:
8136 case 0xDB:
8137 case 0xDC:
8138 case 0xDD:
8139 case 0xDE:
8140 case 0xDF:
8141 {
8142 if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF})))
8143 {
8144 return token_type::parse_error;
8145 }
8146 break;
8147 }
8148
8149 // U+0800..U+0FFF: bytes E0 A0..BF 80..BF
8150 case 0xE0:
8151 {
8152 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))
8153 {
8154 return token_type::parse_error;
8155 }
8156 break;
8157 }
8158
8159 // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF
8160 // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF
8161 case 0xE1:
8162 case 0xE2:
8163 case 0xE3:
8164 case 0xE4:
8165 case 0xE5:
8166 case 0xE6:
8167 case 0xE7:
8168 case 0xE8:
8169 case 0xE9:
8170 case 0xEA:
8171 case 0xEB:
8172 case 0xEC:
8173 case 0xEE:
8174 case 0xEF:
8175 {
8176 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))
8177 {
8178 return token_type::parse_error;
8179 }
8180 break;
8181 }
8182
8183 // U+D000..U+D7FF: bytes ED 80..9F 80..BF
8184 case 0xED:
8185 {
8186 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))
8187 {
8188 return token_type::parse_error;
8189 }
8190 break;
8191 }
8192
8193 // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF
8194 case 0xF0:
8195 {
8196 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
8197 {
8198 return token_type::parse_error;
8199 }
8200 break;
8201 }
8202
8203 // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF
8204 case 0xF1:
8205 case 0xF2:
8206 case 0xF3:
8207 {
8208 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))
8209 {
8210 return token_type::parse_error;
8211 }
8212 break;
8213 }
8214
8215 // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF
8216 case 0xF4:
8217 {
8218 if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))
8219 {
8220 return token_type::parse_error;
8221 }
8222 break;
8223 }
8224
8225 // remaining bytes (80..C1 and F5..FF) are ill-formed
8226 default:
8227 {
8228 error_message = "invalid string: ill-formed UTF-8 byte";
8229 return token_type::parse_error;
8230 }
8231 }
8232 }
8233 }
8234
8240 {
8241 switch (get())
8242 {
8243 // single-line comments skip input until a newline or EOF is read
8244 case '/':
8245 {
8246 while (true)
8247 {
8248 switch (get())
8249 {
8250 case '\n':
8251 case '\r':
8253 case '\0':
8254 return true;
8255
8256 default:
8257 break;
8258 }
8259 }
8260 }
8261
8262 // multi-line comments skip input until */ is read
8263 case '*':
8264 {
8265 while (true)
8266 {
8267 switch (get())
8268 {
8270 case '\0':
8271 {
8272 error_message = "invalid comment; missing closing '*/'";
8273 return false;
8274 }
8275
8276 case '*':
8277 {
8278 switch (get())
8279 {
8280 case '/':
8281 return true;
8282
8283 default:
8284 {
8285 unget();
8286 continue;
8287 }
8288 }
8289 }
8290
8291 default:
8292 continue;
8293 }
8294 }
8295 }
8296
8297 // unexpected character after reading '/'
8298 default:
8299 {
8300 error_message = "invalid comment; expecting '/' or '*' after '/'";
8301 return false;
8302 }
8303 }
8304 }
8305
8306 JSON_HEDLEY_NON_NULL(2)
8307 static void strtof(float& f, const char* str, char** endptr) noexcept
8308 {
8309 f = std::strtof(str, endptr);
8310 }
8311
8312 JSON_HEDLEY_NON_NULL(2)
8313 static void strtof(double& f, const char* str, char** endptr) noexcept
8314 {
8315 f = std::strtod(str, endptr);
8316 }
8317
8318 JSON_HEDLEY_NON_NULL(2)
8319 static void strtof(long double& f, const char* str, char** endptr) noexcept
8320 {
8321 f = std::strtold(str, endptr);
8322 }
8323
8364 token_type scan_number() // lgtm [cpp/use-of-goto]
8365 {
8366 // reset token_buffer to store the number's bytes
8367 reset();
8368
8369 // the type of the parsed number; initially set to unsigned; will be
8370 // changed if minus sign, decimal point or exponent is read
8371 token_type number_type = token_type::value_unsigned;
8372
8373 // state (init): we just found out we need to scan a number
8374 switch (current)
8375 {
8376 case '-':
8377 {
8378 add(current);
8379 goto scan_number_minus;
8380 }
8381
8382 case '0':
8383 {
8384 add(current);
8385 goto scan_number_zero;
8386 }
8387
8388 case '1':
8389 case '2':
8390 case '3':
8391 case '4':
8392 case '5':
8393 case '6':
8394 case '7':
8395 case '8':
8396 case '9':
8397 {
8398 add(current);
8399 goto scan_number_any1;
8400 }
8401
8402 // all other characters are rejected outside scan_number()
8403 default: // LCOV_EXCL_LINE
8404 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
8405 }
8406
8407scan_number_minus:
8408 // state: we just parsed a leading minus sign
8409 number_type = token_type::value_integer;
8410 switch (get())
8411 {
8412 case '0':
8413 {
8414 add(current);
8415 goto scan_number_zero;
8416 }
8417
8418 case '1':
8419 case '2':
8420 case '3':
8421 case '4':
8422 case '5':
8423 case '6':
8424 case '7':
8425 case '8':
8426 case '9':
8427 {
8428 add(current);
8429 goto scan_number_any1;
8430 }
8431
8432 default:
8433 {
8434 error_message = "invalid number; expected digit after '-'";
8435 return token_type::parse_error;
8436 }
8437 }
8438
8439scan_number_zero:
8440 // state: we just parse a zero (maybe with a leading minus sign)
8441 switch (get())
8442 {
8443 case '.':
8444 {
8445 add(decimal_point_char);
8446 goto scan_number_decimal1;
8447 }
8448
8449 case 'e':
8450 case 'E':
8451 {
8452 add(current);
8453 goto scan_number_exponent;
8454 }
8455
8456 default:
8457 goto scan_number_done;
8458 }
8459
8460scan_number_any1:
8461 // state: we just parsed a number 0-9 (maybe with a leading minus sign)
8462 switch (get())
8463 {
8464 case '0':
8465 case '1':
8466 case '2':
8467 case '3':
8468 case '4':
8469 case '5':
8470 case '6':
8471 case '7':
8472 case '8':
8473 case '9':
8474 {
8475 add(current);
8476 goto scan_number_any1;
8477 }
8478
8479 case '.':
8480 {
8481 add(decimal_point_char);
8482 goto scan_number_decimal1;
8483 }
8484
8485 case 'e':
8486 case 'E':
8487 {
8488 add(current);
8489 goto scan_number_exponent;
8490 }
8491
8492 default:
8493 goto scan_number_done;
8494 }
8495
8496scan_number_decimal1:
8497 // state: we just parsed a decimal point
8498 number_type = token_type::value_float;
8499 switch (get())
8500 {
8501 case '0':
8502 case '1':
8503 case '2':
8504 case '3':
8505 case '4':
8506 case '5':
8507 case '6':
8508 case '7':
8509 case '8':
8510 case '9':
8511 {
8512 add(current);
8513 goto scan_number_decimal2;
8514 }
8515
8516 default:
8517 {
8518 error_message = "invalid number; expected digit after '.'";
8519 return token_type::parse_error;
8520 }
8521 }
8522
8523scan_number_decimal2:
8524 // we just parsed at least one number after a decimal point
8525 switch (get())
8526 {
8527 case '0':
8528 case '1':
8529 case '2':
8530 case '3':
8531 case '4':
8532 case '5':
8533 case '6':
8534 case '7':
8535 case '8':
8536 case '9':
8537 {
8538 add(current);
8539 goto scan_number_decimal2;
8540 }
8541
8542 case 'e':
8543 case 'E':
8544 {
8545 add(current);
8546 goto scan_number_exponent;
8547 }
8548
8549 default:
8550 goto scan_number_done;
8551 }
8552
8553scan_number_exponent:
8554 // we just parsed an exponent
8555 number_type = token_type::value_float;
8556 switch (get())
8557 {
8558 case '+':
8559 case '-':
8560 {
8561 add(current);
8562 goto scan_number_sign;
8563 }
8564
8565 case '0':
8566 case '1':
8567 case '2':
8568 case '3':
8569 case '4':
8570 case '5':
8571 case '6':
8572 case '7':
8573 case '8':
8574 case '9':
8575 {
8576 add(current);
8577 goto scan_number_any2;
8578 }
8579
8580 default:
8581 {
8582 error_message =
8583 "invalid number; expected '+', '-', or digit after exponent";
8584 return token_type::parse_error;
8585 }
8586 }
8587
8588scan_number_sign:
8589 // we just parsed an exponent sign
8590 switch (get())
8591 {
8592 case '0':
8593 case '1':
8594 case '2':
8595 case '3':
8596 case '4':
8597 case '5':
8598 case '6':
8599 case '7':
8600 case '8':
8601 case '9':
8602 {
8603 add(current);
8604 goto scan_number_any2;
8605 }
8606
8607 default:
8608 {
8609 error_message = "invalid number; expected digit after exponent sign";
8610 return token_type::parse_error;
8611 }
8612 }
8613
8614scan_number_any2:
8615 // we just parsed a number after the exponent or exponent sign
8616 switch (get())
8617 {
8618 case '0':
8619 case '1':
8620 case '2':
8621 case '3':
8622 case '4':
8623 case '5':
8624 case '6':
8625 case '7':
8626 case '8':
8627 case '9':
8628 {
8629 add(current);
8630 goto scan_number_any2;
8631 }
8632
8633 default:
8634 goto scan_number_done;
8635 }
8636
8637scan_number_done:
8638 // unget the character after the number (we only read it to know that
8639 // we are done scanning a number)
8640 unget();
8641
8642 char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
8643 errno = 0;
8644
8645 // try to parse integers first and fall back to floats
8646 if (number_type == token_type::value_unsigned)
8647 {
8648 const auto x = std::strtoull(token_buffer.data(), &endptr, 10);
8649
8650 // we checked the number format before
8651 JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
8652
8653 if (errno == 0)
8654 {
8655 value_unsigned = static_cast<number_unsigned_t>(x);
8656 if (value_unsigned == x)
8657 {
8658 return token_type::value_unsigned;
8659 }
8660 }
8661 }
8662 else if (number_type == token_type::value_integer)
8663 {
8664 const auto x = std::strtoll(token_buffer.data(), &endptr, 10);
8665
8666 // we checked the number format before
8667 JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
8668
8669 if (errno == 0)
8670 {
8671 value_integer = static_cast<number_integer_t>(x);
8672 if (value_integer == x)
8673 {
8674 return token_type::value_integer;
8675 }
8676 }
8677 }
8678
8679 // this code is reached if we parse a floating-point number or if an
8680 // integer conversion above failed
8681 strtof(value_float, token_buffer.data(), &endptr);
8682
8683 // we checked the number format before
8684 JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());
8685
8686 return token_type::value_float;
8687 }
8688
8694 JSON_HEDLEY_NON_NULL(2)
8695 token_type scan_literal(const char_type* literal_text, const std::size_t length,
8696 token_type return_type)
8697 {
8698 JSON_ASSERT(char_traits<char_type>::to_char_type(current) == literal_text[0]);
8699 for (std::size_t i = 1; i < length; ++i)
8700 {
8701 if (JSON_HEDLEY_UNLIKELY(char_traits<char_type>::to_char_type(get()) != literal_text[i]))
8702 {
8703 error_message = "invalid literal";
8704 return token_type::parse_error;
8705 }
8706 }
8707 return return_type;
8708 }
8709
8711 // input management
8713
8715 void reset() noexcept
8716 {
8717 token_buffer.clear();
8718 token_string.clear();
8719 token_string.push_back(char_traits<char_type>::to_char_type(current));
8720 }
8721
8722 /*
8723 @brief get next character from the input
8724
8725 This function provides the interface to the used input adapter. It does
8726 not throw in case the input reached EOF, but returns a
8727 `char_traits<char>::eof()` in that case. Stores the scanned characters
8728 for use in error messages.
8729
8730 @return character read from the input
8731 */
8732 char_int_type get()
8733 {
8734 ++position.chars_read_total;
8735 ++position.chars_read_current_line;
8736
8737 if (next_unget)
8738 {
8739 // just reset the next_unget variable and work with current
8740 next_unget = false;
8741 }
8742 else
8743 {
8744 current = ia.get_character();
8745 }
8746
8747 if (JSON_HEDLEY_LIKELY(current != char_traits<char_type>::eof()))
8748 {
8749 token_string.push_back(char_traits<char_type>::to_char_type(current));
8750 }
8751
8752 if (current == '\n')
8753 {
8754 ++position.lines_read;
8755 position.chars_read_current_line = 0;
8756 }
8757
8758 return current;
8759 }
8760
8769 void unget()
8770 {
8771 next_unget = true;
8772
8773 --position.chars_read_total;
8774
8775 // in case we "unget" a newline, we have to also decrement the lines_read
8776 if (position.chars_read_current_line == 0)
8777 {
8778 if (position.lines_read > 0)
8779 {
8780 --position.lines_read;
8781 }
8782 }
8783 else
8784 {
8785 --position.chars_read_current_line;
8786 }
8787
8788 if (JSON_HEDLEY_LIKELY(current != char_traits<char_type>::eof()))
8789 {
8790 JSON_ASSERT(!token_string.empty());
8791 token_string.pop_back();
8792 }
8793 }
8794
8796 void add(char_int_type c)
8797 {
8798 token_buffer.push_back(static_cast<typename string_t::value_type>(c));
8799 }
8800
8801 public:
8803 // value getters
8805
8807 constexpr number_integer_t get_number_integer() const noexcept
8808 {
8809 return value_integer;
8810 }
8811
8813 constexpr number_unsigned_t get_number_unsigned() const noexcept
8814 {
8815 return value_unsigned;
8816 }
8817
8819 constexpr number_float_t get_number_float() const noexcept
8820 {
8821 return value_float;
8822 }
8823
8825 string_t& get_string()
8826 {
8827 return token_buffer;
8828 }
8829
8831 // diagnostics
8833
8835 constexpr position_t get_position() const noexcept
8836 {
8837 return position;
8838 }
8839
8843 std::string get_token_string() const
8844 {
8845 // escape control characters
8846 std::string result;
8847 for (const auto c : token_string)
8848 {
8849 if (static_cast<unsigned char>(c) <= '\x1F')
8850 {
8851 // escape control characters
8852 std::array<char, 9> cs{{}};
8853 static_cast<void>((std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
8854 result += cs.data();
8855 }
8856 else
8857 {
8858 // add character as is
8859 result.push_back(static_cast<std::string::value_type>(c));
8860 }
8861 }
8862
8863 return result;
8864 }
8865
8867 JSON_HEDLEY_RETURNS_NON_NULL
8868 constexpr const char* get_error_message() const noexcept
8869 {
8870 return error_message;
8871 }
8872
8874 // actual scanner
8876
8882 {
8883 if (get() == 0xEF)
8884 {
8885 // check if we completely parse the BOM
8886 return get() == 0xBB && get() == 0xBF;
8887 }
8888
8889 // the first character is not the beginning of the BOM; unget it to
8890 // process is later
8891 unget();
8892 return true;
8893 }
8894
8895 void skip_whitespace()
8896 {
8897 do
8898 {
8899 get();
8900 }
8901 while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
8902 }
8903
8904 token_type scan()
8905 {
8906 // initially, skip the BOM
8907 if (position.chars_read_total == 0 && !skip_bom())
8908 {
8909 error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
8910 return token_type::parse_error;
8911 }
8912
8913 // read next character and ignore whitespace
8914 skip_whitespace();
8915
8916 // ignore comments
8917 while (ignore_comments && current == '/')
8918 {
8919 if (!scan_comment())
8920 {
8921 return token_type::parse_error;
8922 }
8923
8924 // skip following whitespace
8925 skip_whitespace();
8926 }
8927
8928 switch (current)
8929 {
8930 // structural characters
8931 case '[':
8932 return token_type::begin_array;
8933 case ']':
8934 return token_type::end_array;
8935 case '{':
8936 return token_type::begin_object;
8937 case '}':
8938 return token_type::end_object;
8939 case ':':
8940 return token_type::name_separator;
8941 case ',':
8942 return token_type::value_separator;
8943
8944 // literals
8945 case 't':
8946 {
8947 std::array<char_type, 4> true_literal = {{static_cast<char_type>('t'), static_cast<char_type>('r'), static_cast<char_type>('u'), static_cast<char_type>('e')}};
8948 return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true);
8949 }
8950 case 'f':
8951 {
8952 std::array<char_type, 5> false_literal = {{static_cast<char_type>('f'), static_cast<char_type>('a'), static_cast<char_type>('l'), static_cast<char_type>('s'), static_cast<char_type>('e')}};
8953 return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false);
8954 }
8955 case 'n':
8956 {
8957 std::array<char_type, 4> null_literal = {{static_cast<char_type>('n'), static_cast<char_type>('u'), static_cast<char_type>('l'), static_cast<char_type>('l')}};
8958 return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null);
8959 }
8960
8961 // string
8962 case '\"':
8963 return scan_string();
8964
8965 // number
8966 case '-':
8967 case '0':
8968 case '1':
8969 case '2':
8970 case '3':
8971 case '4':
8972 case '5':
8973 case '6':
8974 case '7':
8975 case '8':
8976 case '9':
8977 return scan_number();
8978
8979 // end of input (the null byte is needed when parsing from
8980 // string literals)
8981 case '\0':
8982 case char_traits<char_type>::eof():
8983 return token_type::end_of_input;
8984
8985 // error
8986 default:
8987 error_message = "invalid literal";
8988 return token_type::parse_error;
8989 }
8990 }
8991
8992 private:
8994 InputAdapterType ia;
8995
8997 const bool ignore_comments = false;
8998
9000 char_int_type current = char_traits<char_type>::eof();
9001
9003 bool next_unget = false;
9004
9006 position_t position {};
9007
9009 std::vector<char_type> token_string {};
9010
9012 string_t token_buffer {};
9013
9015 const char* error_message = "";
9016
9017 // number values
9018 number_integer_t value_integer = 0;
9019 number_unsigned_t value_unsigned = 0;
9020 number_float_t value_float = 0;
9021
9023 const char_int_type decimal_point_char = '.';
9024};
9025
9026} // namespace detail
9027NLOHMANN_JSON_NAMESPACE_END
9028
9029// #include <nlohmann/detail/macro_scope.hpp>
9030
9031// #include <nlohmann/detail/meta/is_sax.hpp>
9032// __ _____ _____ _____
9033// __| | __| | | | JSON for Modern C++
9034// | | |__ | | | | | | version 3.11.3
9035// |_____|_____|_____|_|___| https://github.com/nlohmann/json
9036//
9037// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
9038// SPDX-License-Identifier: MIT
9039
9040
9041
9042#include <cstdint> // size_t
9043#include <utility> // declval
9044#include <string> // string
9045
9046// #include <nlohmann/detail/abi_macros.hpp>
9047
9048// #include <nlohmann/detail/meta/detected.hpp>
9049
9050// #include <nlohmann/detail/meta/type_traits.hpp>
9051
9052
9053NLOHMANN_JSON_NAMESPACE_BEGIN
9054namespace detail
9055{
9056
9057template<typename T>
9058using null_function_t = decltype(std::declval<T&>().null());
9059
9060template<typename T>
9061using boolean_function_t =
9062 decltype(std::declval<T&>().boolean(std::declval<bool>()));
9063
9064template<typename T, typename Integer>
9065using number_integer_function_t =
9066 decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
9067
9068template<typename T, typename Unsigned>
9069using number_unsigned_function_t =
9070 decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));
9071
9072template<typename T, typename Float, typename String>
9073using number_float_function_t = decltype(std::declval<T&>().number_float(
9074 std::declval<Float>(), std::declval<const String&>()));
9075
9076template<typename T, typename String>
9077using string_function_t =
9078 decltype(std::declval<T&>().string(std::declval<String&>()));
9079
9080template<typename T, typename Binary>
9081using binary_function_t =
9082 decltype(std::declval<T&>().binary(std::declval<Binary&>()));
9083
9084template<typename T>
9085using start_object_function_t =
9086 decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));
9087
9088template<typename T, typename String>
9089using key_function_t =
9090 decltype(std::declval<T&>().key(std::declval<String&>()));
9091
9092template<typename T>
9093using end_object_function_t = decltype(std::declval<T&>().end_object());
9094
9095template<typename T>
9096using start_array_function_t =
9097 decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));
9098
9099template<typename T>
9100using end_array_function_t = decltype(std::declval<T&>().end_array());
9101
9102template<typename T, typename Exception>
9103using parse_error_function_t = decltype(std::declval<T&>().parse_error(
9104 std::declval<std::size_t>(), std::declval<const std::string&>(),
9105 std::declval<const Exception&>()));
9106
9107template<typename SAX, typename BasicJsonType>
9109{
9110 private:
9112 "BasicJsonType must be of type basic_json<...>");
9113
9114 using number_integer_t = typename BasicJsonType::number_integer_t;
9115 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
9116 using number_float_t = typename BasicJsonType::number_float_t;
9117 using string_t = typename BasicJsonType::string_t;
9118 using binary_t = typename BasicJsonType::binary_t;
9119 using exception_t = typename BasicJsonType::exception;
9120
9121 public:
9122 static constexpr bool value =
9123 is_detected_exact<bool, null_function_t, SAX>::value &&
9124 is_detected_exact<bool, boolean_function_t, SAX>::value &&
9125 is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&
9126 is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&
9127 is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&
9128 is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
9129 is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&
9130 is_detected_exact<bool, start_object_function_t, SAX>::value &&
9131 is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
9132 is_detected_exact<bool, end_object_function_t, SAX>::value &&
9133 is_detected_exact<bool, start_array_function_t, SAX>::value &&
9134 is_detected_exact<bool, end_array_function_t, SAX>::value &&
9135 is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
9136};
9137
9138template<typename SAX, typename BasicJsonType>
9140{
9141 private:
9143 "BasicJsonType must be of type basic_json<...>");
9144
9145 using number_integer_t = typename BasicJsonType::number_integer_t;
9146 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
9147 using number_float_t = typename BasicJsonType::number_float_t;
9148 using string_t = typename BasicJsonType::string_t;
9149 using binary_t = typename BasicJsonType::binary_t;
9150 using exception_t = typename BasicJsonType::exception;
9151
9152 public:
9153 static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
9154 "Missing/invalid function: bool null()");
9155 static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
9156 "Missing/invalid function: bool boolean(bool)");
9157 static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
9158 "Missing/invalid function: bool boolean(bool)");
9159 static_assert(
9160 is_detected_exact<bool, number_integer_function_t, SAX,
9161 number_integer_t>::value,
9162 "Missing/invalid function: bool number_integer(number_integer_t)");
9163 static_assert(
9164 is_detected_exact<bool, number_unsigned_function_t, SAX,
9165 number_unsigned_t>::value,
9166 "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
9167 static_assert(is_detected_exact<bool, number_float_function_t, SAX,
9168 number_float_t, string_t>::value,
9169 "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
9170 static_assert(
9171 is_detected_exact<bool, string_function_t, SAX, string_t>::value,
9172 "Missing/invalid function: bool string(string_t&)");
9173 static_assert(
9174 is_detected_exact<bool, binary_function_t, SAX, binary_t>::value,
9175 "Missing/invalid function: bool binary(binary_t&)");
9176 static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
9177 "Missing/invalid function: bool start_object(std::size_t)");
9178 static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
9179 "Missing/invalid function: bool key(string_t&)");
9180 static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
9181 "Missing/invalid function: bool end_object()");
9182 static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
9183 "Missing/invalid function: bool start_array(std::size_t)");
9184 static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
9185 "Missing/invalid function: bool end_array()");
9186 static_assert(
9187 is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
9188 "Missing/invalid function: bool parse_error(std::size_t, const "
9189 "std::string&, const exception&)");
9190};
9191
9192} // namespace detail
9193NLOHMANN_JSON_NAMESPACE_END
9194
9195// #include <nlohmann/detail/meta/type_traits.hpp>
9196
9197// #include <nlohmann/detail/string_concat.hpp>
9198
9199// #include <nlohmann/detail/value_t.hpp>
9200
9201
9202NLOHMANN_JSON_NAMESPACE_BEGIN
9203namespace detail
9204{
9205
9208{
9209 error,
9210 ignore,
9211 store
9212};
9213
9221static inline bool little_endianness(int num = 1) noexcept
9222{
9223 return *reinterpret_cast<char*>(&num) == 1;
9224}
9225
9227// binary reader //
9229
9233template<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType>>
9235{
9236 using number_integer_t = typename BasicJsonType::number_integer_t;
9237 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
9238 using number_float_t = typename BasicJsonType::number_float_t;
9239 using string_t = typename BasicJsonType::string_t;
9240 using binary_t = typename BasicJsonType::binary_t;
9241 using json_sax_t = SAX;
9242 using char_type = typename InputAdapterType::char_type;
9243 using char_int_type = typename char_traits<char_type>::int_type;
9244
9245 public:
9251 explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json) noexcept : ia(std::move(adapter)), input_format(format)
9252 {
9254 }
9255
9256 // make class move-only
9257 binary_reader(const binary_reader&) = delete;
9258 binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
9259 binary_reader& operator=(const binary_reader&) = delete;
9260 binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
9261 ~binary_reader() = default;
9262
9271 JSON_HEDLEY_NON_NULL(3)
9272 bool sax_parse(const input_format_t format,
9273 json_sax_t* sax_,
9274 const bool strict = true,
9275 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
9276 {
9277 sax = sax_;
9278 bool result = false;
9279
9280 switch (format)
9281 {
9282 case input_format_t::bson:
9283 result = parse_bson_internal();
9284 break;
9285
9286 case input_format_t::cbor:
9287 result = parse_cbor_internal(true, tag_handler);
9288 break;
9289
9290 case input_format_t::msgpack:
9291 result = parse_msgpack_internal();
9292 break;
9293
9294 case input_format_t::ubjson:
9295 case input_format_t::bjdata:
9296 result = parse_ubjson_internal();
9297 break;
9298
9299 case input_format_t::json: // LCOV_EXCL_LINE
9300 default: // LCOV_EXCL_LINE
9301 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
9302 }
9303
9304 // strict mode: next byte must be EOF
9305 if (result && strict)
9306 {
9307 if (input_format == input_format_t::ubjson || input_format == input_format_t::bjdata)
9308 {
9309 get_ignore_noop();
9310 }
9311 else
9312 {
9313 get();
9314 }
9315
9316 if (JSON_HEDLEY_UNLIKELY(current != char_traits<char_type>::eof()))
9317 {
9318 return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read,
9319 exception_message(input_format, concat("expected end of input; last byte: 0x", get_token_string()), "value"), nullptr));
9320 }
9321 }
9322
9323 return result;
9324 }
9325
9326 private:
9328 // BSON //
9330
9336 {
9337 std::int32_t document_size{};
9338 get_number<std::int32_t, true>(input_format_t::bson, document_size);
9339
9340 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
9341 {
9342 return false;
9343 }
9344
9345 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false)))
9346 {
9347 return false;
9348 }
9349
9350 return sax->end_object();
9351 }
9352
9360 bool get_bson_cstr(string_t& result)
9361 {
9362 auto out = std::back_inserter(result);
9363 while (true)
9364 {
9365 get();
9366 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "cstring")))
9367 {
9368 return false;
9369 }
9370 if (current == 0x00)
9371 {
9372 return true;
9373 }
9374 *out++ = static_cast<typename string_t::value_type>(current);
9375 }
9376 }
9377
9389 template<typename NumberType>
9390 bool get_bson_string(const NumberType len, string_t& result)
9391 {
9392 if (JSON_HEDLEY_UNLIKELY(len < 1))
9393 {
9394 auto last_token = get_token_string();
9395 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
9396 exception_message(input_format_t::bson, concat("string length must be at least 1, is ", std::to_string(len)), "string"), nullptr));
9397 }
9398
9399 return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != char_traits<char_type>::eof();
9400 }
9401
9411 template<typename NumberType>
9412 bool get_bson_binary(const NumberType len, binary_t& result)
9413 {
9414 if (JSON_HEDLEY_UNLIKELY(len < 0))
9415 {
9416 auto last_token = get_token_string();
9417 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
9418 exception_message(input_format_t::bson, concat("byte array length cannot be negative, is ", std::to_string(len)), "binary"), nullptr));
9419 }
9420
9421 // All BSON binary values have a subtype
9422 std::uint8_t subtype{};
9423 get_number<std::uint8_t>(input_format_t::bson, subtype);
9424 result.set_subtype(subtype);
9425
9426 return get_binary(input_format_t::bson, len, result);
9427 }
9428
9439 bool parse_bson_element_internal(const char_int_type element_type,
9440 const std::size_t element_type_parse_position)
9441 {
9442 switch (element_type)
9443 {
9444 case 0x01: // double
9445 {
9446 double number{};
9447 return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), "");
9448 }
9449
9450 case 0x02: // string
9451 {
9452 std::int32_t len{};
9453 string_t value;
9454 return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value);
9455 }
9456
9457 case 0x03: // object
9458 {
9459 return parse_bson_internal();
9460 }
9461
9462 case 0x04: // array
9463 {
9464 return parse_bson_array();
9465 }
9466
9467 case 0x05: // binary
9468 {
9469 std::int32_t len{};
9470 binary_t value;
9471 return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value);
9472 }
9473
9474 case 0x08: // boolean
9475 {
9476 return sax->boolean(get() != 0);
9477 }
9478
9479 case 0x0A: // null
9480 {
9481 return sax->null();
9482 }
9483
9484 case 0x10: // int32
9485 {
9486 std::int32_t value{};
9487 return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);
9488 }
9489
9490 case 0x12: // int64
9491 {
9492 std::int64_t value{};
9493 return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);
9494 }
9495
9496 default: // anything else not supported (yet)
9497 {
9498 std::array<char, 3> cr{{}};
9499 static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
9500 const std::string cr_str{cr.data()};
9501 return sax->parse_error(element_type_parse_position, cr_str,
9502 parse_error::create(114, element_type_parse_position, concat("Unsupported BSON record type 0x", cr_str), nullptr));
9503 }
9504 }
9505 }
9506
9519 bool parse_bson_element_list(const bool is_array)
9520 {
9521 string_t key;
9522
9523 while (auto element_type = get())
9524 {
9525 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, "element list")))
9526 {
9527 return false;
9528 }
9529
9530 const std::size_t element_type_parse_position = chars_read;
9531 if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))
9532 {
9533 return false;
9534 }
9535
9536 if (!is_array && !sax->key(key))
9537 {
9538 return false;
9539 }
9540
9541 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position)))
9542 {
9543 return false;
9544 }
9545
9546 // get_bson_cstr only appends
9547 key.clear();
9548 }
9549
9550 return true;
9551 }
9552
9558 {
9559 std::int32_t document_size{};
9560 get_number<std::int32_t, true>(input_format_t::bson, document_size);
9561
9562 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
9563 {
9564 return false;
9565 }
9566
9567 if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true)))
9568 {
9569 return false;
9570 }
9571
9572 return sax->end_array();
9573 }
9574
9576 // CBOR //
9578
9587 bool parse_cbor_internal(const bool get_char,
9588 const cbor_tag_handler_t tag_handler)
9589 {
9590 switch (get_char ? get() : current)
9591 {
9592 // EOF
9594 return unexpect_eof(input_format_t::cbor, "value");
9595
9596 // Integer 0x00..0x17 (0..23)
9597 case 0x00:
9598 case 0x01:
9599 case 0x02:
9600 case 0x03:
9601 case 0x04:
9602 case 0x05:
9603 case 0x06:
9604 case 0x07:
9605 case 0x08:
9606 case 0x09:
9607 case 0x0A:
9608 case 0x0B:
9609 case 0x0C:
9610 case 0x0D:
9611 case 0x0E:
9612 case 0x0F:
9613 case 0x10:
9614 case 0x11:
9615 case 0x12:
9616 case 0x13:
9617 case 0x14:
9618 case 0x15:
9619 case 0x16:
9620 case 0x17:
9621 return sax->number_unsigned(static_cast<number_unsigned_t>(current));
9622
9623 case 0x18: // Unsigned integer (one-byte uint8_t follows)
9624 {
9625 std::uint8_t number{};
9626 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
9627 }
9628
9629 case 0x19: // Unsigned integer (two-byte uint16_t follows)
9630 {
9631 std::uint16_t number{};
9632 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
9633 }
9634
9635 case 0x1A: // Unsigned integer (four-byte uint32_t follows)
9636 {
9637 std::uint32_t number{};
9638 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
9639 }
9640
9641 case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
9642 {
9643 std::uint64_t number{};
9644 return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);
9645 }
9646
9647 // Negative integer -1-0x00..-1-0x17 (-1..-24)
9648 case 0x20:
9649 case 0x21:
9650 case 0x22:
9651 case 0x23:
9652 case 0x24:
9653 case 0x25:
9654 case 0x26:
9655 case 0x27:
9656 case 0x28:
9657 case 0x29:
9658 case 0x2A:
9659 case 0x2B:
9660 case 0x2C:
9661 case 0x2D:
9662 case 0x2E:
9663 case 0x2F:
9664 case 0x30:
9665 case 0x31:
9666 case 0x32:
9667 case 0x33:
9668 case 0x34:
9669 case 0x35:
9670 case 0x36:
9671 case 0x37:
9672 return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
9673
9674 case 0x38: // Negative integer (one-byte uint8_t follows)
9675 {
9676 std::uint8_t number{};
9677 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
9678 }
9679
9680 case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
9681 {
9682 std::uint16_t number{};
9683 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
9684 }
9685
9686 case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
9687 {
9688 std::uint32_t number{};
9689 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);
9690 }
9691
9692 case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
9693 {
9694 std::uint64_t number{};
9695 return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)
9696 - static_cast<number_integer_t>(number));
9697 }
9698
9699 // Binary data (0x00..0x17 bytes follow)
9700 case 0x40:
9701 case 0x41:
9702 case 0x42:
9703 case 0x43:
9704 case 0x44:
9705 case 0x45:
9706 case 0x46:
9707 case 0x47:
9708 case 0x48:
9709 case 0x49:
9710 case 0x4A:
9711 case 0x4B:
9712 case 0x4C:
9713 case 0x4D:
9714 case 0x4E:
9715 case 0x4F:
9716 case 0x50:
9717 case 0x51:
9718 case 0x52:
9719 case 0x53:
9720 case 0x54:
9721 case 0x55:
9722 case 0x56:
9723 case 0x57:
9724 case 0x58: // Binary data (one-byte uint8_t for n follows)
9725 case 0x59: // Binary data (two-byte uint16_t for n follow)
9726 case 0x5A: // Binary data (four-byte uint32_t for n follow)
9727 case 0x5B: // Binary data (eight-byte uint64_t for n follow)
9728 case 0x5F: // Binary data (indefinite length)
9729 {
9730 binary_t b;
9731 return get_cbor_binary(b) && sax->binary(b);
9732 }
9733
9734 // UTF-8 string (0x00..0x17 bytes follow)
9735 case 0x60:
9736 case 0x61:
9737 case 0x62:
9738 case 0x63:
9739 case 0x64:
9740 case 0x65:
9741 case 0x66:
9742 case 0x67:
9743 case 0x68:
9744 case 0x69:
9745 case 0x6A:
9746 case 0x6B:
9747 case 0x6C:
9748 case 0x6D:
9749 case 0x6E:
9750 case 0x6F:
9751 case 0x70:
9752 case 0x71:
9753 case 0x72:
9754 case 0x73:
9755 case 0x74:
9756 case 0x75:
9757 case 0x76:
9758 case 0x77:
9759 case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
9760 case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
9761 case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
9762 case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
9763 case 0x7F: // UTF-8 string (indefinite length)
9764 {
9765 string_t s;
9766 return get_cbor_string(s) && sax->string(s);
9767 }
9768
9769 // array (0x00..0x17 data items follow)
9770 case 0x80:
9771 case 0x81:
9772 case 0x82:
9773 case 0x83:
9774 case 0x84:
9775 case 0x85:
9776 case 0x86:
9777 case 0x87:
9778 case 0x88:
9779 case 0x89:
9780 case 0x8A:
9781 case 0x8B:
9782 case 0x8C:
9783 case 0x8D:
9784 case 0x8E:
9785 case 0x8F:
9786 case 0x90:
9787 case 0x91:
9788 case 0x92:
9789 case 0x93:
9790 case 0x94:
9791 case 0x95:
9792 case 0x96:
9793 case 0x97:
9794 return get_cbor_array(
9795 conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
9796
9797 case 0x98: // array (one-byte uint8_t for n follows)
9798 {
9799 std::uint8_t len{};
9800 return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
9801 }
9802
9803 case 0x99: // array (two-byte uint16_t for n follow)
9804 {
9805 std::uint16_t len{};
9806 return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);
9807 }
9808
9809 case 0x9A: // array (four-byte uint32_t for n follow)
9810 {
9811 std::uint32_t len{};
9812 return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
9813 }
9814
9815 case 0x9B: // array (eight-byte uint64_t for n follow)
9816 {
9817 std::uint64_t len{};
9818 return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);
9819 }
9820
9821 case 0x9F: // array (indefinite length)
9822 return get_cbor_array(static_cast<std::size_t>(-1), tag_handler);
9823
9824 // map (0x00..0x17 pairs of data items follow)
9825 case 0xA0:
9826 case 0xA1:
9827 case 0xA2:
9828 case 0xA3:
9829 case 0xA4:
9830 case 0xA5:
9831 case 0xA6:
9832 case 0xA7:
9833 case 0xA8:
9834 case 0xA9:
9835 case 0xAA:
9836 case 0xAB:
9837 case 0xAC:
9838 case 0xAD:
9839 case 0xAE:
9840 case 0xAF:
9841 case 0xB0:
9842 case 0xB1:
9843 case 0xB2:
9844 case 0xB3:
9845 case 0xB4:
9846 case 0xB5:
9847 case 0xB6:
9848 case 0xB7:
9849 return get_cbor_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);
9850
9851 case 0xB8: // map (one-byte uint8_t for n follows)
9852 {
9853 std::uint8_t len{};
9854 return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
9855 }
9856
9857 case 0xB9: // map (two-byte uint16_t for n follow)
9858 {
9859 std::uint16_t len{};
9860 return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);
9861 }
9862
9863 case 0xBA: // map (four-byte uint32_t for n follow)
9864 {
9865 std::uint32_t len{};
9866 return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
9867 }
9868
9869 case 0xBB: // map (eight-byte uint64_t for n follow)
9870 {
9871 std::uint64_t len{};
9872 return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);
9873 }
9874
9875 case 0xBF: // map (indefinite length)
9876 return get_cbor_object(static_cast<std::size_t>(-1), tag_handler);
9877
9878 case 0xC6: // tagged item
9879 case 0xC7:
9880 case 0xC8:
9881 case 0xC9:
9882 case 0xCA:
9883 case 0xCB:
9884 case 0xCC:
9885 case 0xCD:
9886 case 0xCE:
9887 case 0xCF:
9888 case 0xD0:
9889 case 0xD1:
9890 case 0xD2:
9891 case 0xD3:
9892 case 0xD4:
9893 case 0xD8: // tagged item (1 bytes follow)
9894 case 0xD9: // tagged item (2 bytes follow)
9895 case 0xDA: // tagged item (4 bytes follow)
9896 case 0xDB: // tagged item (8 bytes follow)
9897 {
9898 switch (tag_handler)
9899 {
9900 case cbor_tag_handler_t::error:
9901 {
9902 auto last_token = get_token_string();
9903 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
9904 exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr));
9905 }
9906
9907 case cbor_tag_handler_t::ignore:
9908 {
9909 // ignore binary subtype
9910 switch (current)
9911 {
9912 case 0xD8:
9913 {
9914 std::uint8_t subtype_to_ignore{};
9915 get_number(input_format_t::cbor, subtype_to_ignore);
9916 break;
9917 }
9918 case 0xD9:
9919 {
9920 std::uint16_t subtype_to_ignore{};
9921 get_number(input_format_t::cbor, subtype_to_ignore);
9922 break;
9923 }
9924 case 0xDA:
9925 {
9926 std::uint32_t subtype_to_ignore{};
9927 get_number(input_format_t::cbor, subtype_to_ignore);
9928 break;
9929 }
9930 case 0xDB:
9931 {
9932 std::uint64_t subtype_to_ignore{};
9933 get_number(input_format_t::cbor, subtype_to_ignore);
9934 break;
9935 }
9936 default:
9937 break;
9938 }
9939 return parse_cbor_internal(true, tag_handler);
9940 }
9941
9942 case cbor_tag_handler_t::store:
9943 {
9944 binary_t b;
9945 // use binary subtype and store in binary container
9946 switch (current)
9947 {
9948 case 0xD8:
9949 {
9950 std::uint8_t subtype{};
9951 get_number(input_format_t::cbor, subtype);
9952 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
9953 break;
9954 }
9955 case 0xD9:
9956 {
9957 std::uint16_t subtype{};
9958 get_number(input_format_t::cbor, subtype);
9959 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
9960 break;
9961 }
9962 case 0xDA:
9963 {
9964 std::uint32_t subtype{};
9965 get_number(input_format_t::cbor, subtype);
9966 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
9967 break;
9968 }
9969 case 0xDB:
9970 {
9971 std::uint64_t subtype{};
9972 get_number(input_format_t::cbor, subtype);
9973 b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));
9974 break;
9975 }
9976 default:
9977 return parse_cbor_internal(true, tag_handler);
9978 }
9979 get();
9980 return get_cbor_binary(b) && sax->binary(b);
9981 }
9982
9983 default: // LCOV_EXCL_LINE
9984 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
9985 return false; // LCOV_EXCL_LINE
9986 }
9987 }
9988
9989 case 0xF4: // false
9990 return sax->boolean(false);
9991
9992 case 0xF5: // true
9993 return sax->boolean(true);
9994
9995 case 0xF6: // null
9996 return sax->null();
9997
9998 case 0xF9: // Half-Precision Float (two-byte IEEE 754)
9999 {
10000 const auto byte1_raw = get();
10001 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
10002 {
10003 return false;
10004 }
10005 const auto byte2_raw = get();
10006 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "number")))
10007 {
10008 return false;
10009 }
10010
10011 const auto byte1 = static_cast<unsigned char>(byte1_raw);
10012 const auto byte2 = static_cast<unsigned char>(byte2_raw);
10013
10014 // code from RFC 7049, Appendix D, Figure 3:
10015 // As half-precision floating-point numbers were only added
10016 // to IEEE 754 in 2008, today's programming platforms often
10017 // still only have limited support for them. It is very
10018 // easy to include at least decoding support for them even
10019 // without such support. An example of a small decoder for
10020 // half-precision floating-point numbers in the C language
10021 // is shown in Fig. 3.
10022 const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);
10023 const double val = [&half]
10024 {
10025 const int exp = (half >> 10u) & 0x1Fu;
10026 const unsigned int mant = half & 0x3FFu;
10027 JSON_ASSERT(0 <= exp&& exp <= 32);
10028 JSON_ASSERT(mant <= 1024);
10029 switch (exp)
10030 {
10031 case 0:
10032 return std::ldexp(mant, -24);
10033 case 31:
10034 return (mant == 0)
10035 ? std::numeric_limits<double>::infinity()
10036 : std::numeric_limits<double>::quiet_NaN();
10037 default:
10038 return std::ldexp(mant + 1024, exp - 25);
10039 }
10040 }();
10041 return sax->number_float((half & 0x8000u) != 0
10042 ? static_cast<number_float_t>(-val)
10043 : static_cast<number_float_t>(val), "");
10044 }
10045
10046 case 0xFA: // Single-Precision Float (four-byte IEEE 754)
10047 {
10048 float number{};
10049 return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
10050 }
10051
10052 case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
10053 {
10054 double number{};
10055 return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), "");
10056 }
10057
10058 default: // anything else (0xFF is handled inside the other types)
10059 {
10060 auto last_token = get_token_string();
10061 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
10062 exception_message(input_format_t::cbor, concat("invalid byte: 0x", last_token), "value"), nullptr));
10063 }
10064 }
10065 }
10066
10078 bool get_cbor_string(string_t& result)
10079 {
10080 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "string")))
10081 {
10082 return false;
10083 }
10084
10085 switch (current)
10086 {
10087 // UTF-8 string (0x00..0x17 bytes follow)
10088 case 0x60:
10089 case 0x61:
10090 case 0x62:
10091 case 0x63:
10092 case 0x64:
10093 case 0x65:
10094 case 0x66:
10095 case 0x67:
10096 case 0x68:
10097 case 0x69:
10098 case 0x6A:
10099 case 0x6B:
10100 case 0x6C:
10101 case 0x6D:
10102 case 0x6E:
10103 case 0x6F:
10104 case 0x70:
10105 case 0x71:
10106 case 0x72:
10107 case 0x73:
10108 case 0x74:
10109 case 0x75:
10110 case 0x76:
10111 case 0x77:
10112 {
10113 return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
10114 }
10115
10116 case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
10117 {
10118 std::uint8_t len{};
10119 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
10120 }
10121
10122 case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
10123 {
10124 std::uint16_t len{};
10125 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
10126 }
10127
10128 case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
10129 {
10130 std::uint32_t len{};
10131 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
10132 }
10133
10134 case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
10135 {
10136 std::uint64_t len{};
10137 return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);
10138 }
10139
10140 case 0x7F: // UTF-8 string (indefinite length)
10141 {
10142 while (get() != 0xFF)
10143 {
10144 string_t chunk;
10145 if (!get_cbor_string(chunk))
10146 {
10147 return false;
10148 }
10149 result.append(chunk);
10150 }
10151 return true;
10152 }
10153
10154 default:
10155 {
10156 auto last_token = get_token_string();
10157 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
10158 exception_message(input_format_t::cbor, concat("expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x", last_token), "string"), nullptr));
10159 }
10160 }
10161 }
10162
10174 bool get_cbor_binary(binary_t& result)
10175 {
10176 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, "binary")))
10177 {
10178 return false;
10179 }
10180
10181 switch (current)
10182 {
10183 // Binary data (0x00..0x17 bytes follow)
10184 case 0x40:
10185 case 0x41:
10186 case 0x42:
10187 case 0x43:
10188 case 0x44:
10189 case 0x45:
10190 case 0x46:
10191 case 0x47:
10192 case 0x48:
10193 case 0x49:
10194 case 0x4A:
10195 case 0x4B:
10196 case 0x4C:
10197 case 0x4D:
10198 case 0x4E:
10199 case 0x4F:
10200 case 0x50:
10201 case 0x51:
10202 case 0x52:
10203 case 0x53:
10204 case 0x54:
10205 case 0x55:
10206 case 0x56:
10207 case 0x57:
10208 {
10209 return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
10210 }
10211
10212 case 0x58: // Binary data (one-byte uint8_t for n follows)
10213 {
10214 std::uint8_t len{};
10215 return get_number(input_format_t::cbor, len) &&
10216 get_binary(input_format_t::cbor, len, result);
10217 }
10218
10219 case 0x59: // Binary data (two-byte uint16_t for n follow)
10220 {
10221 std::uint16_t len{};
10222 return get_number(input_format_t::cbor, len) &&
10223 get_binary(input_format_t::cbor, len, result);
10224 }
10225
10226 case 0x5A: // Binary data (four-byte uint32_t for n follow)
10227 {
10228 std::uint32_t len{};
10229 return get_number(input_format_t::cbor, len) &&
10230 get_binary(input_format_t::cbor, len, result);
10231 }
10232
10233 case 0x5B: // Binary data (eight-byte uint64_t for n follow)
10234 {
10235 std::uint64_t len{};
10236 return get_number(input_format_t::cbor, len) &&
10237 get_binary(input_format_t::cbor, len, result);
10238 }
10239
10240 case 0x5F: // Binary data (indefinite length)
10241 {
10242 while (get() != 0xFF)
10243 {
10244 binary_t chunk;
10245 if (!get_cbor_binary(chunk))
10246 {
10247 return false;
10248 }
10249 result.insert(result.end(), chunk.begin(), chunk.end());
10250 }
10251 return true;
10252 }
10253
10254 default:
10255 {
10256 auto last_token = get_token_string();
10257 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
10258 exception_message(input_format_t::cbor, concat("expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x", last_token), "binary"), nullptr));
10259 }
10260 }
10261 }
10262
10269 bool get_cbor_array(const std::size_t len,
10270 const cbor_tag_handler_t tag_handler)
10271 {
10272 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
10273 {
10274 return false;
10275 }
10276
10277 if (len != static_cast<std::size_t>(-1))
10278 {
10279 for (std::size_t i = 0; i < len; ++i)
10280 {
10281 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
10282 {
10283 return false;
10284 }
10285 }
10286 }
10287 else
10288 {
10289 while (get() != 0xFF)
10290 {
10291 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler)))
10292 {
10293 return false;
10294 }
10295 }
10296 }
10297
10298 return sax->end_array();
10299 }
10300
10307 bool get_cbor_object(const std::size_t len,
10308 const cbor_tag_handler_t tag_handler)
10309 {
10310 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
10311 {
10312 return false;
10313 }
10314
10315 if (len != 0)
10316 {
10317 string_t key;
10318 if (len != static_cast<std::size_t>(-1))
10319 {
10320 for (std::size_t i = 0; i < len; ++i)
10321 {
10322 get();
10323 if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
10324 {
10325 return false;
10326 }
10327
10328 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
10329 {
10330 return false;
10331 }
10332 key.clear();
10333 }
10334 }
10335 else
10336 {
10337 while (get() != 0xFF)
10338 {
10339 if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))
10340 {
10341 return false;
10342 }
10343
10344 if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))
10345 {
10346 return false;
10347 }
10348 key.clear();
10349 }
10350 }
10351 }
10352
10353 return sax->end_object();
10354 }
10355
10357 // MsgPack //
10359
10364 {
10365 switch (get())
10366 {
10367 // EOF
10369 return unexpect_eof(input_format_t::msgpack, "value");
10370
10371 // positive fixint
10372 case 0x00:
10373 case 0x01:
10374 case 0x02:
10375 case 0x03:
10376 case 0x04:
10377 case 0x05:
10378 case 0x06:
10379 case 0x07:
10380 case 0x08:
10381 case 0x09:
10382 case 0x0A:
10383 case 0x0B:
10384 case 0x0C:
10385 case 0x0D:
10386 case 0x0E:
10387 case 0x0F:
10388 case 0x10:
10389 case 0x11:
10390 case 0x12:
10391 case 0x13:
10392 case 0x14:
10393 case 0x15:
10394 case 0x16:
10395 case 0x17:
10396 case 0x18:
10397 case 0x19:
10398 case 0x1A:
10399 case 0x1B:
10400 case 0x1C:
10401 case 0x1D:
10402 case 0x1E:
10403 case 0x1F:
10404 case 0x20:
10405 case 0x21:
10406 case 0x22:
10407 case 0x23:
10408 case 0x24:
10409 case 0x25:
10410 case 0x26:
10411 case 0x27:
10412 case 0x28:
10413 case 0x29:
10414 case 0x2A:
10415 case 0x2B:
10416 case 0x2C:
10417 case 0x2D:
10418 case 0x2E:
10419 case 0x2F:
10420 case 0x30:
10421 case 0x31:
10422 case 0x32:
10423 case 0x33:
10424 case 0x34:
10425 case 0x35:
10426 case 0x36:
10427 case 0x37:
10428 case 0x38:
10429 case 0x39:
10430 case 0x3A:
10431 case 0x3B:
10432 case 0x3C:
10433 case 0x3D:
10434 case 0x3E:
10435 case 0x3F:
10436 case 0x40:
10437 case 0x41:
10438 case 0x42:
10439 case 0x43:
10440 case 0x44:
10441 case 0x45:
10442 case 0x46:
10443 case 0x47:
10444 case 0x48:
10445 case 0x49:
10446 case 0x4A:
10447 case 0x4B:
10448 case 0x4C:
10449 case 0x4D:
10450 case 0x4E:
10451 case 0x4F:
10452 case 0x50:
10453 case 0x51:
10454 case 0x52:
10455 case 0x53:
10456 case 0x54:
10457 case 0x55:
10458 case 0x56:
10459 case 0x57:
10460 case 0x58:
10461 case 0x59:
10462 case 0x5A:
10463 case 0x5B:
10464 case 0x5C:
10465 case 0x5D:
10466 case 0x5E:
10467 case 0x5F:
10468 case 0x60:
10469 case 0x61:
10470 case 0x62:
10471 case 0x63:
10472 case 0x64:
10473 case 0x65:
10474 case 0x66:
10475 case 0x67:
10476 case 0x68:
10477 case 0x69:
10478 case 0x6A:
10479 case 0x6B:
10480 case 0x6C:
10481 case 0x6D:
10482 case 0x6E:
10483 case 0x6F:
10484 case 0x70:
10485 case 0x71:
10486 case 0x72:
10487 case 0x73:
10488 case 0x74:
10489 case 0x75:
10490 case 0x76:
10491 case 0x77:
10492 case 0x78:
10493 case 0x79:
10494 case 0x7A:
10495 case 0x7B:
10496 case 0x7C:
10497 case 0x7D:
10498 case 0x7E:
10499 case 0x7F:
10500 return sax->number_unsigned(static_cast<number_unsigned_t>(current));
10501
10502 // fixmap
10503 case 0x80:
10504 case 0x81:
10505 case 0x82:
10506 case 0x83:
10507 case 0x84:
10508 case 0x85:
10509 case 0x86:
10510 case 0x87:
10511 case 0x88:
10512 case 0x89:
10513 case 0x8A:
10514 case 0x8B:
10515 case 0x8C:
10516 case 0x8D:
10517 case 0x8E:
10518 case 0x8F:
10519 return get_msgpack_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
10520
10521 // fixarray
10522 case 0x90:
10523 case 0x91:
10524 case 0x92:
10525 case 0x93:
10526 case 0x94:
10527 case 0x95:
10528 case 0x96:
10529 case 0x97:
10530 case 0x98:
10531 case 0x99:
10532 case 0x9A:
10533 case 0x9B:
10534 case 0x9C:
10535 case 0x9D:
10536 case 0x9E:
10537 case 0x9F:
10538 return get_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
10539
10540 // fixstr
10541 case 0xA0:
10542 case 0xA1:
10543 case 0xA2:
10544 case 0xA3:
10545 case 0xA4:
10546 case 0xA5:
10547 case 0xA6:
10548 case 0xA7:
10549 case 0xA8:
10550 case 0xA9:
10551 case 0xAA:
10552 case 0xAB:
10553 case 0xAC:
10554 case 0xAD:
10555 case 0xAE:
10556 case 0xAF:
10557 case 0xB0:
10558 case 0xB1:
10559 case 0xB2:
10560 case 0xB3:
10561 case 0xB4:
10562 case 0xB5:
10563 case 0xB6:
10564 case 0xB7:
10565 case 0xB8:
10566 case 0xB9:
10567 case 0xBA:
10568 case 0xBB:
10569 case 0xBC:
10570 case 0xBD:
10571 case 0xBE:
10572 case 0xBF:
10573 case 0xD9: // str 8
10574 case 0xDA: // str 16
10575 case 0xDB: // str 32
10576 {
10577 string_t s;
10578 return get_msgpack_string(s) && sax->string(s);
10579 }
10580
10581 case 0xC0: // nil
10582 return sax->null();
10583
10584 case 0xC2: // false
10585 return sax->boolean(false);
10586
10587 case 0xC3: // true
10588 return sax->boolean(true);
10589
10590 case 0xC4: // bin 8
10591 case 0xC5: // bin 16
10592 case 0xC6: // bin 32
10593 case 0xC7: // ext 8
10594 case 0xC8: // ext 16
10595 case 0xC9: // ext 32
10596 case 0xD4: // fixext 1
10597 case 0xD5: // fixext 2
10598 case 0xD6: // fixext 4
10599 case 0xD7: // fixext 8
10600 case 0xD8: // fixext 16
10601 {
10602 binary_t b;
10603 return get_msgpack_binary(b) && sax->binary(b);
10604 }
10605
10606 case 0xCA: // float 32
10607 {
10608 float number{};
10609 return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
10610 }
10611
10612 case 0xCB: // float 64
10613 {
10614 double number{};
10615 return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), "");
10616 }
10617
10618 case 0xCC: // uint 8
10619 {
10620 std::uint8_t number{};
10621 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
10622 }
10623
10624 case 0xCD: // uint 16
10625 {
10626 std::uint16_t number{};
10627 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
10628 }
10629
10630 case 0xCE: // uint 32
10631 {
10632 std::uint32_t number{};
10633 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
10634 }
10635
10636 case 0xCF: // uint 64
10637 {
10638 std::uint64_t number{};
10639 return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);
10640 }
10641
10642 case 0xD0: // int 8
10643 {
10644 std::int8_t number{};
10645 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
10646 }
10647
10648 case 0xD1: // int 16
10649 {
10650 std::int16_t number{};
10651 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
10652 }
10653
10654 case 0xD2: // int 32
10655 {
10656 std::int32_t number{};
10657 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
10658 }
10659
10660 case 0xD3: // int 64
10661 {
10662 std::int64_t number{};
10663 return get_number(input_format_t::msgpack, number) && sax->number_integer(number);
10664 }
10665
10666 case 0xDC: // array 16
10667 {
10668 std::uint16_t len{};
10669 return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));
10670 }
10671
10672 case 0xDD: // array 32
10673 {
10674 std::uint32_t len{};
10675 return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast<std::size_t>(len));
10676 }
10677
10678 case 0xDE: // map 16
10679 {
10680 std::uint16_t len{};
10681 return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));
10682 }
10683
10684 case 0xDF: // map 32
10685 {
10686 std::uint32_t len{};
10687 return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast<std::size_t>(len));
10688 }
10689
10690 // negative fixint
10691 case 0xE0:
10692 case 0xE1:
10693 case 0xE2:
10694 case 0xE3:
10695 case 0xE4:
10696 case 0xE5:
10697 case 0xE6:
10698 case 0xE7:
10699 case 0xE8:
10700 case 0xE9:
10701 case 0xEA:
10702 case 0xEB:
10703 case 0xEC:
10704 case 0xED:
10705 case 0xEE:
10706 case 0xEF:
10707 case 0xF0:
10708 case 0xF1:
10709 case 0xF2:
10710 case 0xF3:
10711 case 0xF4:
10712 case 0xF5:
10713 case 0xF6:
10714 case 0xF7:
10715 case 0xF8:
10716 case 0xF9:
10717 case 0xFA:
10718 case 0xFB:
10719 case 0xFC:
10720 case 0xFD:
10721 case 0xFE:
10722 case 0xFF:
10723 return sax->number_integer(static_cast<std::int8_t>(current));
10724
10725 default: // anything else
10726 {
10727 auto last_token = get_token_string();
10728 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
10729 exception_message(input_format_t::msgpack, concat("invalid byte: 0x", last_token), "value"), nullptr));
10730 }
10731 }
10732 }
10733
10744 bool get_msgpack_string(string_t& result)
10745 {
10746 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, "string")))
10747 {
10748 return false;
10749 }
10750
10751 switch (current)
10752 {
10753 // fixstr
10754 case 0xA0:
10755 case 0xA1:
10756 case 0xA2:
10757 case 0xA3:
10758 case 0xA4:
10759 case 0xA5:
10760 case 0xA6:
10761 case 0xA7:
10762 case 0xA8:
10763 case 0xA9:
10764 case 0xAA:
10765 case 0xAB:
10766 case 0xAC:
10767 case 0xAD:
10768 case 0xAE:
10769 case 0xAF:
10770 case 0xB0:
10771 case 0xB1:
10772 case 0xB2:
10773 case 0xB3:
10774 case 0xB4:
10775 case 0xB5:
10776 case 0xB6:
10777 case 0xB7:
10778 case 0xB8:
10779 case 0xB9:
10780 case 0xBA:
10781 case 0xBB:
10782 case 0xBC:
10783 case 0xBD:
10784 case 0xBE:
10785 case 0xBF:
10786 {
10787 return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);
10788 }
10789
10790 case 0xD9: // str 8
10791 {
10792 std::uint8_t len{};
10793 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
10794 }
10795
10796 case 0xDA: // str 16
10797 {
10798 std::uint16_t len{};
10799 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
10800 }
10801
10802 case 0xDB: // str 32
10803 {
10804 std::uint32_t len{};
10805 return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);
10806 }
10807
10808 default:
10809 {
10810 auto last_token = get_token_string();
10811 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
10812 exception_message(input_format_t::msgpack, concat("expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x", last_token), "string"), nullptr));
10813 }
10814 }
10815 }
10816
10827 bool get_msgpack_binary(binary_t& result)
10828 {
10829 // helper function to set the subtype
10830 auto assign_and_return_true = [&result](std::int8_t subtype)
10831 {
10832 result.set_subtype(static_cast<std::uint8_t>(subtype));
10833 return true;
10834 };
10835
10836 switch (current)
10837 {
10838 case 0xC4: // bin 8
10839 {
10840 std::uint8_t len{};
10841 return get_number(input_format_t::msgpack, len) &&
10842 get_binary(input_format_t::msgpack, len, result);
10843 }
10844
10845 case 0xC5: // bin 16
10846 {
10847 std::uint16_t len{};
10848 return get_number(input_format_t::msgpack, len) &&
10849 get_binary(input_format_t::msgpack, len, result);
10850 }
10851
10852 case 0xC6: // bin 32
10853 {
10854 std::uint32_t len{};
10855 return get_number(input_format_t::msgpack, len) &&
10856 get_binary(input_format_t::msgpack, len, result);
10857 }
10858
10859 case 0xC7: // ext 8
10860 {
10861 std::uint8_t len{};
10862 std::int8_t subtype{};
10863 return get_number(input_format_t::msgpack, len) &&
10864 get_number(input_format_t::msgpack, subtype) &&
10865 get_binary(input_format_t::msgpack, len, result) &&
10866 assign_and_return_true(subtype);
10867 }
10868
10869 case 0xC8: // ext 16
10870 {
10871 std::uint16_t len{};
10872 std::int8_t subtype{};
10873 return get_number(input_format_t::msgpack, len) &&
10874 get_number(input_format_t::msgpack, subtype) &&
10875 get_binary(input_format_t::msgpack, len, result) &&
10876 assign_and_return_true(subtype);
10877 }
10878
10879 case 0xC9: // ext 32
10880 {
10881 std::uint32_t len{};
10882 std::int8_t subtype{};
10883 return get_number(input_format_t::msgpack, len) &&
10884 get_number(input_format_t::msgpack, subtype) &&
10885 get_binary(input_format_t::msgpack, len, result) &&
10886 assign_and_return_true(subtype);
10887 }
10888
10889 case 0xD4: // fixext 1
10890 {
10891 std::int8_t subtype{};
10892 return get_number(input_format_t::msgpack, subtype) &&
10893 get_binary(input_format_t::msgpack, 1, result) &&
10894 assign_and_return_true(subtype);
10895 }
10896
10897 case 0xD5: // fixext 2
10898 {
10899 std::int8_t subtype{};
10900 return get_number(input_format_t::msgpack, subtype) &&
10901 get_binary(input_format_t::msgpack, 2, result) &&
10902 assign_and_return_true(subtype);
10903 }
10904
10905 case 0xD6: // fixext 4
10906 {
10907 std::int8_t subtype{};
10908 return get_number(input_format_t::msgpack, subtype) &&
10909 get_binary(input_format_t::msgpack, 4, result) &&
10910 assign_and_return_true(subtype);
10911 }
10912
10913 case 0xD7: // fixext 8
10914 {
10915 std::int8_t subtype{};
10916 return get_number(input_format_t::msgpack, subtype) &&
10917 get_binary(input_format_t::msgpack, 8, result) &&
10918 assign_and_return_true(subtype);
10919 }
10920
10921 case 0xD8: // fixext 16
10922 {
10923 std::int8_t subtype{};
10924 return get_number(input_format_t::msgpack, subtype) &&
10925 get_binary(input_format_t::msgpack, 16, result) &&
10926 assign_and_return_true(subtype);
10927 }
10928
10929 default: // LCOV_EXCL_LINE
10930 return false; // LCOV_EXCL_LINE
10931 }
10932 }
10933
10938 bool get_msgpack_array(const std::size_t len)
10939 {
10940 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))
10941 {
10942 return false;
10943 }
10944
10945 for (std::size_t i = 0; i < len; ++i)
10946 {
10947 if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
10948 {
10949 return false;
10950 }
10951 }
10952
10953 return sax->end_array();
10954 }
10955
10960 bool get_msgpack_object(const std::size_t len)
10961 {
10962 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))
10963 {
10964 return false;
10965 }
10966
10967 string_t key;
10968 for (std::size_t i = 0; i < len; ++i)
10969 {
10970 get();
10971 if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))
10972 {
10973 return false;
10974 }
10975
10976 if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))
10977 {
10978 return false;
10979 }
10980 key.clear();
10981 }
10982
10983 return sax->end_object();
10984 }
10985
10987 // UBJSON //
10989
10997 bool parse_ubjson_internal(const bool get_char = true)
10998 {
10999 return get_ubjson_value(get_char ? get_ignore_noop() : current);
11000 }
11001
11016 bool get_ubjson_string(string_t& result, const bool get_char = true)
11017 {
11018 if (get_char)
11019 {
11020 get(); // TODO(niels): may we ignore N here?
11021 }
11022
11023 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
11024 {
11025 return false;
11026 }
11027
11028 switch (current)
11029 {
11030 case 'U':
11031 {
11032 std::uint8_t len{};
11033 return get_number(input_format, len) && get_string(input_format, len, result);
11034 }
11035
11036 case 'i':
11037 {
11038 std::int8_t len{};
11039 return get_number(input_format, len) && get_string(input_format, len, result);
11040 }
11041
11042 case 'I':
11043 {
11044 std::int16_t len{};
11045 return get_number(input_format, len) && get_string(input_format, len, result);
11046 }
11047
11048 case 'l':
11049 {
11050 std::int32_t len{};
11051 return get_number(input_format, len) && get_string(input_format, len, result);
11052 }
11053
11054 case 'L':
11055 {
11056 std::int64_t len{};
11057 return get_number(input_format, len) && get_string(input_format, len, result);
11058 }
11059
11060 case 'u':
11061 {
11062 if (input_format != input_format_t::bjdata)
11063 {
11064 break;
11065 }
11066 std::uint16_t len{};
11067 return get_number(input_format, len) && get_string(input_format, len, result);
11068 }
11069
11070 case 'm':
11071 {
11072 if (input_format != input_format_t::bjdata)
11073 {
11074 break;
11075 }
11076 std::uint32_t len{};
11077 return get_number(input_format, len) && get_string(input_format, len, result);
11078 }
11079
11080 case 'M':
11081 {
11082 if (input_format != input_format_t::bjdata)
11083 {
11084 break;
11085 }
11086 std::uint64_t len{};
11087 return get_number(input_format, len) && get_string(input_format, len, result);
11088 }
11089
11090 default:
11091 break;
11092 }
11093 auto last_token = get_token_string();
11094 std::string message;
11095
11096 if (input_format != input_format_t::bjdata)
11097 {
11098 message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
11099 }
11100 else
11101 {
11102 message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
11103 }
11104 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr));
11105 }
11106
11111 bool get_ubjson_ndarray_size(std::vector<size_t>& dim)
11112 {
11113 std::pair<std::size_t, char_int_type> size_and_type;
11114 size_t dimlen = 0;
11115 bool no_ndarray = true;
11116
11117 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray)))
11118 {
11119 return false;
11120 }
11121
11122 if (size_and_type.first != npos)
11123 {
11124 if (size_and_type.second != 0)
11125 {
11126 if (size_and_type.second != 'N')
11127 {
11128 for (std::size_t i = 0; i < size_and_type.first; ++i)
11129 {
11130 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second)))
11131 {
11132 return false;
11133 }
11134 dim.push_back(dimlen);
11135 }
11136 }
11137 }
11138 else
11139 {
11140 for (std::size_t i = 0; i < size_and_type.first; ++i)
11141 {
11142 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray)))
11143 {
11144 return false;
11145 }
11146 dim.push_back(dimlen);
11147 }
11148 }
11149 }
11150 else
11151 {
11152 while (current != ']')
11153 {
11154 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current)))
11155 {
11156 return false;
11157 }
11158 dim.push_back(dimlen);
11159 get_ignore_noop();
11160 }
11161 }
11162 return true;
11163 }
11164
11176 bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0)
11177 {
11178 if (prefix == 0)
11179 {
11180 prefix = get_ignore_noop();
11181 }
11182
11183 switch (prefix)
11184 {
11185 case 'U':
11186 {
11187 std::uint8_t number{};
11188 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11189 {
11190 return false;
11191 }
11192 result = static_cast<std::size_t>(number);
11193 return true;
11194 }
11195
11196 case 'i':
11197 {
11198 std::int8_t number{};
11199 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11200 {
11201 return false;
11202 }
11203 if (number < 0)
11204 {
11205 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
11206 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
11207 }
11208 result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
11209 return true;
11210 }
11211
11212 case 'I':
11213 {
11214 std::int16_t number{};
11215 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11216 {
11217 return false;
11218 }
11219 if (number < 0)
11220 {
11221 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
11222 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
11223 }
11224 result = static_cast<std::size_t>(number);
11225 return true;
11226 }
11227
11228 case 'l':
11229 {
11230 std::int32_t number{};
11231 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11232 {
11233 return false;
11234 }
11235 if (number < 0)
11236 {
11237 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
11238 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
11239 }
11240 result = static_cast<std::size_t>(number);
11241 return true;
11242 }
11243
11244 case 'L':
11245 {
11246 std::int64_t number{};
11247 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11248 {
11249 return false;
11250 }
11251 if (number < 0)
11252 {
11253 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
11254 exception_message(input_format, "count in an optimized container must be positive", "size"), nullptr));
11255 }
11256 if (!value_in_range_of<std::size_t>(number))
11257 {
11258 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
11259 exception_message(input_format, "integer value overflow", "size"), nullptr));
11260 }
11261 result = static_cast<std::size_t>(number);
11262 return true;
11263 }
11264
11265 case 'u':
11266 {
11267 if (input_format != input_format_t::bjdata)
11268 {
11269 break;
11270 }
11271 std::uint16_t number{};
11272 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11273 {
11274 return false;
11275 }
11276 result = static_cast<std::size_t>(number);
11277 return true;
11278 }
11279
11280 case 'm':
11281 {
11282 if (input_format != input_format_t::bjdata)
11283 {
11284 break;
11285 }
11286 std::uint32_t number{};
11287 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11288 {
11289 return false;
11290 }
11291 result = conditional_static_cast<std::size_t>(number);
11292 return true;
11293 }
11294
11295 case 'M':
11296 {
11297 if (input_format != input_format_t::bjdata)
11298 {
11299 break;
11300 }
11301 std::uint64_t number{};
11302 if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))
11303 {
11304 return false;
11305 }
11306 if (!value_in_range_of<std::size_t>(number))
11307 {
11308 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,
11309 exception_message(input_format, "integer value overflow", "size"), nullptr));
11310 }
11311 result = detail::conditional_static_cast<std::size_t>(number);
11312 return true;
11313 }
11314
11315 case '[':
11316 {
11317 if (input_format != input_format_t::bjdata)
11318 {
11319 break;
11320 }
11321 if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array
11322 {
11323 return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, "ndarray dimensional vector is not allowed", "size"), nullptr));
11324 }
11325 std::vector<size_t> dim;
11326 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim)))
11327 {
11328 return false;
11329 }
11330 if (dim.size() == 1 || (dim.size() == 2 && dim.at(0) == 1)) // return normal array size if 1D row vector
11331 {
11332 result = dim.at(dim.size() - 1);
11333 return true;
11334 }
11335 if (!dim.empty()) // if ndarray, convert to an object in JData annotated array format
11336 {
11337 for (auto i : dim) // test if any dimension in an ndarray is 0, if so, return a 1D empty container
11338 {
11339 if ( i == 0 )
11340 {
11341 result = 0;
11342 return true;
11343 }
11344 }
11345
11346 string_t key = "_ArraySize_";
11347 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size())))
11348 {
11349 return false;
11350 }
11351 result = 1;
11352 for (auto i : dim)
11353 {
11354 result *= i;
11355 if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type()
11356 {
11357 return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, "excessive ndarray size caused overflow", "size"), nullptr));
11358 }
11359 if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast<number_unsigned_t>(i))))
11360 {
11361 return false;
11362 }
11363 }
11364 is_ndarray = true;
11365 return sax->end_array();
11366 }
11367 result = 0;
11368 return true;
11369 }
11370
11371 default:
11372 break;
11373 }
11374 auto last_token = get_token_string();
11375 std::string message;
11376
11377 if (input_format != input_format_t::bjdata)
11378 {
11379 message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
11380 }
11381 else
11382 {
11383 message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
11384 }
11385 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr));
11386 }
11387
11399 bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result, bool inside_ndarray = false)
11400 {
11401 result.first = npos; // size
11402 result.second = 0; // type
11403 bool is_ndarray = false;
11404
11405 get_ignore_noop();
11406
11407 if (current == '$')
11408 {
11409 result.second = get(); // must not ignore 'N', because 'N' maybe the type
11410 if (input_format == input_format_t::bjdata
11411 && JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second)))
11412 {
11413 auto last_token = get_token_string();
11414 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
11415 exception_message(input_format, concat("marker 0x", last_token, " is not a permitted optimized array type"), "type"), nullptr));
11416 }
11417
11418 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "type")))
11419 {
11420 return false;
11421 }
11422
11423 get_ignore_noop();
11424 if (JSON_HEDLEY_UNLIKELY(current != '#'))
11425 {
11426 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "value")))
11427 {
11428 return false;
11429 }
11430 auto last_token = get_token_string();
11431 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
11432 exception_message(input_format, concat("expected '#' after type information; last byte: 0x", last_token), "size"), nullptr));
11433 }
11434
11435 const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
11436 if (input_format == input_format_t::bjdata && is_ndarray)
11437 {
11438 if (inside_ndarray)
11439 {
11440 return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
11441 exception_message(input_format, "ndarray can not be recursive", "size"), nullptr));
11442 }
11443 result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters
11444 }
11445 return is_error;
11446 }
11447
11448 if (current == '#')
11449 {
11450 const bool is_error = get_ubjson_size_value(result.first, is_ndarray);
11451 if (input_format == input_format_t::bjdata && is_ndarray)
11452 {
11453 return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,
11454 exception_message(input_format, "ndarray requires both type and size", "size"), nullptr));
11455 }
11456 return is_error;
11457 }
11458
11459 return true;
11460 }
11461
11466 bool get_ubjson_value(const char_int_type prefix)
11467 {
11468 switch (prefix)
11469 {
11470 case char_traits<char_type>::eof(): // EOF
11471 return unexpect_eof(input_format, "value");
11472
11473 case 'T': // true
11474 return sax->boolean(true);
11475 case 'F': // false
11476 return sax->boolean(false);
11477
11478 case 'Z': // null
11479 return sax->null();
11480
11481 case 'U':
11482 {
11483 std::uint8_t number{};
11484 return get_number(input_format, number) && sax->number_unsigned(number);
11485 }
11486
11487 case 'i':
11488 {
11489 std::int8_t number{};
11490 return get_number(input_format, number) && sax->number_integer(number);
11491 }
11492
11493 case 'I':
11494 {
11495 std::int16_t number{};
11496 return get_number(input_format, number) && sax->number_integer(number);
11497 }
11498
11499 case 'l':
11500 {
11501 std::int32_t number{};
11502 return get_number(input_format, number) && sax->number_integer(number);
11503 }
11504
11505 case 'L':
11506 {
11507 std::int64_t number{};
11508 return get_number(input_format, number) && sax->number_integer(number);
11509 }
11510
11511 case 'u':
11512 {
11513 if (input_format != input_format_t::bjdata)
11514 {
11515 break;
11516 }
11517 std::uint16_t number{};
11518 return get_number(input_format, number) && sax->number_unsigned(number);
11519 }
11520
11521 case 'm':
11522 {
11523 if (input_format != input_format_t::bjdata)
11524 {
11525 break;
11526 }
11527 std::uint32_t number{};
11528 return get_number(input_format, number) && sax->number_unsigned(number);
11529 }
11530
11531 case 'M':
11532 {
11533 if (input_format != input_format_t::bjdata)
11534 {
11535 break;
11536 }
11537 std::uint64_t number{};
11538 return get_number(input_format, number) && sax->number_unsigned(number);
11539 }
11540
11541 case 'h':
11542 {
11543 if (input_format != input_format_t::bjdata)
11544 {
11545 break;
11546 }
11547 const auto byte1_raw = get();
11548 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
11549 {
11550 return false;
11551 }
11552 const auto byte2_raw = get();
11553 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
11554 {
11555 return false;
11556 }
11557
11558 const auto byte1 = static_cast<unsigned char>(byte1_raw);
11559 const auto byte2 = static_cast<unsigned char>(byte2_raw);
11560
11561 // code from RFC 7049, Appendix D, Figure 3:
11562 // As half-precision floating-point numbers were only added
11563 // to IEEE 754 in 2008, today's programming platforms often
11564 // still only have limited support for them. It is very
11565 // easy to include at least decoding support for them even
11566 // without such support. An example of a small decoder for
11567 // half-precision floating-point numbers in the C language
11568 // is shown in Fig. 3.
11569 const auto half = static_cast<unsigned int>((byte2 << 8u) + byte1);
11570 const double val = [&half]
11571 {
11572 const int exp = (half >> 10u) & 0x1Fu;
11573 const unsigned int mant = half & 0x3FFu;
11574 JSON_ASSERT(0 <= exp&& exp <= 32);
11575 JSON_ASSERT(mant <= 1024);
11576 switch (exp)
11577 {
11578 case 0:
11579 return std::ldexp(mant, -24);
11580 case 31:
11581 return (mant == 0)
11582 ? std::numeric_limits<double>::infinity()
11583 : std::numeric_limits<double>::quiet_NaN();
11584 default:
11585 return std::ldexp(mant + 1024, exp - 25);
11586 }
11587 }();
11588 return sax->number_float((half & 0x8000u) != 0
11589 ? static_cast<number_float_t>(-val)
11590 : static_cast<number_float_t>(val), "");
11591 }
11592
11593 case 'd':
11594 {
11595 float number{};
11596 return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
11597 }
11598
11599 case 'D':
11600 {
11601 double number{};
11602 return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), "");
11603 }
11604
11605 case 'H':
11606 {
11607 return get_ubjson_high_precision_number();
11608 }
11609
11610 case 'C': // char
11611 {
11612 get();
11613 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "char")))
11614 {
11615 return false;
11616 }
11617 if (JSON_HEDLEY_UNLIKELY(current > 127))
11618 {
11619 auto last_token = get_token_string();
11620 return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
11621 exception_message(input_format, concat("byte after 'C' must be in range 0x00..0x7F; last byte: 0x", last_token), "char"), nullptr));
11622 }
11623 string_t s(1, static_cast<typename string_t::value_type>(current));
11624 return sax->string(s);
11625 }
11626
11627 case 'S': // string
11628 {
11629 string_t s;
11630 return get_ubjson_string(s) && sax->string(s);
11631 }
11632
11633 case '[': // array
11634 return get_ubjson_array();
11635
11636 case '{': // object
11637 return get_ubjson_object();
11638
11639 default: // anything else
11640 break;
11641 }
11642 auto last_token = get_token_string();
11643 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, "invalid byte: 0x" + last_token, "value"), nullptr));
11644 }
11645
11650 {
11651 std::pair<std::size_t, char_int_type> size_and_type;
11652 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
11653 {
11654 return false;
11655 }
11656
11657 // if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata):
11658 // {"_ArrayType_" : "typeid", "_ArraySize_" : [n1, n2, ...], "_ArrayData_" : [v1, v2, ...]}
11659
11660 if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
11661 {
11662 size_and_type.second &= ~(static_cast<char_int_type>(1) << 8); // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker
11663 auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t)
11664 {
11665 return p.first < t;
11666 });
11667 string_t key = "_ArrayType_";
11668 if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second))
11669 {
11670 auto last_token = get_token_string();
11671 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
11672 exception_message(input_format, "invalid byte: 0x" + last_token, "type"), nullptr));
11673 }
11674
11675 string_t type = it->second; // sax->string() takes a reference
11676 if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type)))
11677 {
11678 return false;
11679 }
11680
11681 if (size_and_type.second == 'C')
11682 {
11683 size_and_type.second = 'U';
11684 }
11685
11686 key = "_ArrayData_";
11687 if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) ))
11688 {
11689 return false;
11690 }
11691
11692 for (std::size_t i = 0; i < size_and_type.first; ++i)
11693 {
11694 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
11695 {
11696 return false;
11697 }
11698 }
11699
11700 return (sax->end_array() && sax->end_object());
11701 }
11702
11703 if (size_and_type.first != npos)
11704 {
11705 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))
11706 {
11707 return false;
11708 }
11709
11710 if (size_and_type.second != 0)
11711 {
11712 if (size_and_type.second != 'N')
11713 {
11714 for (std::size_t i = 0; i < size_and_type.first; ++i)
11715 {
11716 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
11717 {
11718 return false;
11719 }
11720 }
11721 }
11722 }
11723 else
11724 {
11725 for (std::size_t i = 0; i < size_and_type.first; ++i)
11726 {
11727 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
11728 {
11729 return false;
11730 }
11731 }
11732 }
11733 }
11734 else
11735 {
11736 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
11737 {
11738 return false;
11739 }
11740
11741 while (current != ']')
11742 {
11743 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false)))
11744 {
11745 return false;
11746 }
11747 get_ignore_noop();
11748 }
11749 }
11750
11751 return sax->end_array();
11752 }
11753
11758 {
11759 std::pair<std::size_t, char_int_type> size_and_type;
11760 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))
11761 {
11762 return false;
11763 }
11764
11765 // do not accept ND-array size in objects in BJData
11766 if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)
11767 {
11768 auto last_token = get_token_string();
11769 return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,
11770 exception_message(input_format, "BJData object does not support ND-array size in optimized format", "object"), nullptr));
11771 }
11772
11773 string_t key;
11774 if (size_and_type.first != npos)
11775 {
11776 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first)))
11777 {
11778 return false;
11779 }
11780
11781 if (size_and_type.second != 0)
11782 {
11783 for (std::size_t i = 0; i < size_and_type.first; ++i)
11784 {
11785 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
11786 {
11787 return false;
11788 }
11789 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))
11790 {
11791 return false;
11792 }
11793 key.clear();
11794 }
11795 }
11796 else
11797 {
11798 for (std::size_t i = 0; i < size_and_type.first; ++i)
11799 {
11800 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))
11801 {
11802 return false;
11803 }
11804 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
11805 {
11806 return false;
11807 }
11808 key.clear();
11809 }
11810 }
11811 }
11812 else
11813 {
11814 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
11815 {
11816 return false;
11817 }
11818
11819 while (current != '}')
11820 {
11821 if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key)))
11822 {
11823 return false;
11824 }
11825 if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))
11826 {
11827 return false;
11828 }
11829 get_ignore_noop();
11830 key.clear();
11831 }
11832 }
11833
11834 return sax->end_object();
11835 }
11836
11837 // Note, no reader for UBJSON binary types is implemented because they do
11838 // not exist
11839
11840 bool get_ubjson_high_precision_number()
11841 {
11842 // get size of following number string
11843 std::size_t size{};
11844 bool no_ndarray = true;
11845 auto res = get_ubjson_size_value(size, no_ndarray);
11846 if (JSON_HEDLEY_UNLIKELY(!res))
11847 {
11848 return res;
11849 }
11850
11851 // get number string
11852 std::vector<char> number_vector;
11853 for (std::size_t i = 0; i < size; ++i)
11854 {
11855 get();
11856 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, "number")))
11857 {
11858 return false;
11859 }
11860 number_vector.push_back(static_cast<char>(current));
11861 }
11862
11863 // parse number string
11864 using ia_type = decltype(detail::input_adapter(number_vector));
11865 auto number_lexer = detail::lexer<BasicJsonType, ia_type>(detail::input_adapter(number_vector), false);
11866 const auto result_number = number_lexer.scan();
11867 const auto number_string = number_lexer.get_token_string();
11868 const auto result_remainder = number_lexer.scan();
11869
11870 using token_type = typename detail::lexer_base<BasicJsonType>::token_type;
11871
11872 if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))
11873 {
11874 return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
11875 exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
11876 }
11877
11878 switch (result_number)
11879 {
11880 case token_type::value_integer:
11881 return sax->number_integer(number_lexer.get_number_integer());
11882 case token_type::value_unsigned:
11883 return sax->number_unsigned(number_lexer.get_number_unsigned());
11884 case token_type::value_float:
11885 return sax->number_float(number_lexer.get_number_float(), std::move(number_string));
11886 case token_type::uninitialized:
11887 case token_type::literal_true:
11888 case token_type::literal_false:
11889 case token_type::literal_null:
11890 case token_type::value_string:
11891 case token_type::begin_array:
11892 case token_type::begin_object:
11893 case token_type::end_array:
11894 case token_type::end_object:
11895 case token_type::name_separator:
11896 case token_type::value_separator:
11897 case token_type::parse_error:
11898 case token_type::end_of_input:
11899 case token_type::literal_or_value:
11900 default:
11901 return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,
11902 exception_message(input_format, concat("invalid number text: ", number_lexer.get_token_string()), "high-precision number"), nullptr));
11903 }
11904 }
11905
11907 // Utility functions //
11909
11919 char_int_type get()
11920 {
11921 ++chars_read;
11922 return current = ia.get_character();
11923 }
11924
11928 char_int_type get_ignore_noop()
11929 {
11930 do
11931 {
11932 get();
11933 }
11934 while (current == 'N');
11935
11936 return current;
11937 }
11938
11939 /*
11940 @brief read a number from the input
11941
11942 @tparam NumberType the type of the number
11943 @param[in] format the current format (for diagnostics)
11944 @param[out] result number of type @a NumberType
11945
11946 @return whether conversion completed
11947
11948 @note This function needs to respect the system's endianness, because
11949 bytes in CBOR, MessagePack, and UBJSON are stored in network order
11950 (big endian) and therefore need reordering on little endian systems.
11951 On the other hand, BSON and BJData use little endian and should reorder
11952 on big endian systems.
11953 */
11954 template<typename NumberType, bool InputIsLittleEndian = false>
11955 bool get_number(const input_format_t format, NumberType& result)
11956 {
11957 // step 1: read input into array with system's byte order
11958 std::array<std::uint8_t, sizeof(NumberType)> vec{};
11959 for (std::size_t i = 0; i < sizeof(NumberType); ++i)
11960 {
11961 get();
11962 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number")))
11963 {
11964 return false;
11965 }
11966
11967 // reverse byte order prior to conversion if necessary
11968 if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata))
11969 {
11970 vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);
11971 }
11972 else
11973 {
11974 vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE
11975 }
11976 }
11977
11978 // step 2: convert array into number of type T and return
11979 std::memcpy(&result, vec.data(), sizeof(NumberType));
11980 return true;
11981 }
11982
11997 template<typename NumberType>
11998 bool get_string(const input_format_t format,
11999 const NumberType len,
12000 string_t& result)
12001 {
12002 bool success = true;
12003 for (NumberType i = 0; i < len; i++)
12004 {
12005 get();
12006 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "string")))
12007 {
12008 success = false;
12009 break;
12010 }
12011 result.push_back(static_cast<typename string_t::value_type>(current));
12012 }
12013 return success;
12014 }
12015
12030 template<typename NumberType>
12031 bool get_binary(const input_format_t format,
12032 const NumberType len,
12033 binary_t& result)
12034 {
12035 bool success = true;
12036 for (NumberType i = 0; i < len; i++)
12037 {
12038 get();
12039 if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "binary")))
12040 {
12041 success = false;
12042 break;
12043 }
12044 result.push_back(static_cast<std::uint8_t>(current));
12045 }
12046 return success;
12047 }
12048
12054 JSON_HEDLEY_NON_NULL(3)
12055 bool unexpect_eof(const input_format_t format, const char* context) const
12056 {
12057 if (JSON_HEDLEY_UNLIKELY(current == char_traits<char_type>::eof()))
12058 {
12059 return sax->parse_error(chars_read, "<end of file>",
12060 parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
12061 }
12062 return true;
12063 }
12064
12068 std::string get_token_string() const
12069 {
12070 std::array<char, 3> cr{{}};
12071 static_cast<void>((std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
12072 return std::string{cr.data()};
12073 }
12074
12081 std::string exception_message(const input_format_t format,
12082 const std::string& detail,
12083 const std::string& context) const
12084 {
12085 std::string error_msg = "syntax error while parsing ";
12086
12087 switch (format)
12088 {
12089 case input_format_t::cbor:
12090 error_msg += "CBOR";
12091 break;
12092
12093 case input_format_t::msgpack:
12094 error_msg += "MessagePack";
12095 break;
12096
12097 case input_format_t::ubjson:
12098 error_msg += "UBJSON";
12099 break;
12100
12101 case input_format_t::bson:
12102 error_msg += "BSON";
12103 break;
12104
12105 case input_format_t::bjdata:
12106 error_msg += "BJData";
12107 break;
12108
12109 case input_format_t::json: // LCOV_EXCL_LINE
12110 default: // LCOV_EXCL_LINE
12111 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
12112 }
12113
12114 return concat(error_msg, ' ', context, ": ", detail);
12115 }
12116
12117 private:
12118 static JSON_INLINE_VARIABLE constexpr std::size_t npos = static_cast<std::size_t>(-1);
12119
12121 InputAdapterType ia;
12122
12124 char_int_type current = char_traits<char_type>::eof();
12125
12127 std::size_t chars_read = 0;
12128
12130 const bool is_little_endian = little_endianness();
12131
12133 const input_format_t input_format = input_format_t::json;
12134
12136 json_sax_t* sax = nullptr;
12137
12138 // excluded markers in bjdata optimized type
12139#define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \
12140 make_array<char_int_type>('F', 'H', 'N', 'S', 'T', 'Z', '[', '{')
12141
12142#define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \
12143 make_array<bjd_type>( \
12144 bjd_type{'C', "char"}, \
12145 bjd_type{'D', "double"}, \
12146 bjd_type{'I', "int16"}, \
12147 bjd_type{'L', "int64"}, \
12148 bjd_type{'M', "uint64"}, \
12149 bjd_type{'U', "uint8"}, \
12150 bjd_type{'d', "single"}, \
12151 bjd_type{'i', "int8"}, \
12152 bjd_type{'l', "int32"}, \
12153 bjd_type{'m', "uint32"}, \
12154 bjd_type{'u', "uint16"})
12155
12156 JSON_PRIVATE_UNLESS_TESTED:
12157 // lookup tables
12158 // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
12159 const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers =
12160 JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_;
12161
12162 using bjd_type = std::pair<char_int_type, string_t>;
12163 // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)
12164 const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map =
12165 JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_;
12166
12167#undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_
12168#undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_
12169};
12170
12171#ifndef JSON_HAS_CPP_17
12172 template<typename BasicJsonType, typename InputAdapterType, typename SAX>
12174#endif
12175
12176} // namespace detail
12177NLOHMANN_JSON_NAMESPACE_END
12178
12179// #include <nlohmann/detail/input/input_adapters.hpp>
12180
12181// #include <nlohmann/detail/input/lexer.hpp>
12182
12183// #include <nlohmann/detail/input/parser.hpp>
12184// __ _____ _____ _____
12185// __| | __| | | | JSON for Modern C++
12186// | | |__ | | | | | | version 3.11.3
12187// |_____|_____|_____|_|___| https://github.com/nlohmann/json
12188//
12189// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
12190// SPDX-License-Identifier: MIT
12191
12192
12193
12194#include <cmath> // isfinite
12195#include <cstdint> // uint8_t
12196#include <functional> // function
12197#include <string> // string
12198#include <utility> // move
12199#include <vector> // vector
12200
12201// #include <nlohmann/detail/exceptions.hpp>
12202
12203// #include <nlohmann/detail/input/input_adapters.hpp>
12204
12205// #include <nlohmann/detail/input/json_sax.hpp>
12206
12207// #include <nlohmann/detail/input/lexer.hpp>
12208
12209// #include <nlohmann/detail/macro_scope.hpp>
12210
12211// #include <nlohmann/detail/meta/is_sax.hpp>
12212
12213// #include <nlohmann/detail/string_concat.hpp>
12214
12215// #include <nlohmann/detail/value_t.hpp>
12216
12217
12218NLOHMANN_JSON_NAMESPACE_BEGIN
12219namespace detail
12220{
12222// parser //
12224
12225enum class parse_event_t : std::uint8_t
12226{
12230 object_end,
12234 array_end,
12236 key,
12238 value
12239};
12240
12241template<typename BasicJsonType>
12242using parser_callback_t =
12243 std::function<bool(int /*depth*/, parse_event_t /*event*/, BasicJsonType& /*parsed*/)>;
12244
12250template<typename BasicJsonType, typename InputAdapterType>
12252{
12253 using number_integer_t = typename BasicJsonType::number_integer_t;
12254 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
12255 using number_float_t = typename BasicJsonType::number_float_t;
12256 using string_t = typename BasicJsonType::string_t;
12258 using token_type = typename lexer_t::token_type;
12259
12260 public:
12262 explicit parser(InputAdapterType&& adapter,
12263 const parser_callback_t<BasicJsonType> cb = nullptr,
12264 const bool allow_exceptions_ = true,
12265 const bool skip_comments = false)
12266 : callback(cb)
12267 , m_lexer(std::move(adapter), skip_comments)
12268 , allow_exceptions(allow_exceptions_)
12269 {
12270 // read first token
12271 get_token();
12272 }
12273
12284 void parse(const bool strict, BasicJsonType& result)
12285 {
12286 if (callback)
12287 {
12288 json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
12289 sax_parse_internal(&sdp);
12290
12291 // in strict mode, input must be completely read
12292 if (strict && (get_token() != token_type::end_of_input))
12293 {
12294 sdp.parse_error(m_lexer.get_position(),
12295 m_lexer.get_token_string(),
12296 parse_error::create(101, m_lexer.get_position(),
12297 exception_message(token_type::end_of_input, "value"), nullptr));
12298 }
12299
12300 // in case of an error, return discarded value
12301 if (sdp.is_errored())
12302 {
12303 result = value_t::discarded;
12304 return;
12305 }
12306
12307 // set top-level value to null if it was discarded by the callback
12308 // function
12309 if (result.is_discarded())
12310 {
12311 result = nullptr;
12312 }
12313 }
12314 else
12315 {
12316 json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
12317 sax_parse_internal(&sdp);
12318
12319 // in strict mode, input must be completely read
12320 if (strict && (get_token() != token_type::end_of_input))
12321 {
12322 sdp.parse_error(m_lexer.get_position(),
12323 m_lexer.get_token_string(),
12324 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
12325 }
12326
12327 // in case of an error, return discarded value
12328 if (sdp.is_errored())
12329 {
12330 result = value_t::discarded;
12331 return;
12332 }
12333 }
12334
12335 result.assert_invariant();
12336 }
12337
12344 bool accept(const bool strict = true)
12345 {
12347 return sax_parse(&sax_acceptor, strict);
12348 }
12349
12350 template<typename SAX>
12351 JSON_HEDLEY_NON_NULL(2)
12352 bool sax_parse(SAX* sax, const bool strict = true)
12353 {
12355 const bool result = sax_parse_internal(sax);
12356
12357 // strict mode: next byte must be EOF
12358 if (result && strict && (get_token() != token_type::end_of_input))
12359 {
12360 return sax->parse_error(m_lexer.get_position(),
12361 m_lexer.get_token_string(),
12362 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
12363 }
12364
12365 return result;
12366 }
12367
12368 private:
12369 template<typename SAX>
12370 JSON_HEDLEY_NON_NULL(2)
12371 bool sax_parse_internal(SAX* sax)
12372 {
12373 // stack to remember the hierarchy of structured values we are parsing
12374 // true = array; false = object
12375 std::vector<bool> states;
12376 // value to avoid a goto (see comment where set to true)
12377 bool skip_to_state_evaluation = false;
12378
12379 while (true)
12380 {
12381 if (!skip_to_state_evaluation)
12382 {
12383 // invariant: get_token() was called before each iteration
12384 switch (last_token)
12385 {
12386 case token_type::begin_object:
12387 {
12388 if (JSON_HEDLEY_UNLIKELY(!sax->start_object(static_cast<std::size_t>(-1))))
12389 {
12390 return false;
12391 }
12392
12393 // closing } -> we are done
12394 if (get_token() == token_type::end_object)
12395 {
12396 if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
12397 {
12398 return false;
12399 }
12400 break;
12401 }
12402
12403 // parse key
12404 if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))
12405 {
12406 return sax->parse_error(m_lexer.get_position(),
12407 m_lexer.get_token_string(),
12408 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
12409 }
12410 if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
12411 {
12412 return false;
12413 }
12414
12415 // parse separator (:)
12416 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
12417 {
12418 return sax->parse_error(m_lexer.get_position(),
12419 m_lexer.get_token_string(),
12420 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
12421 }
12422
12423 // remember we are now inside an object
12424 states.push_back(false);
12425
12426 // parse values
12427 get_token();
12428 continue;
12429 }
12430
12431 case token_type::begin_array:
12432 {
12433 if (JSON_HEDLEY_UNLIKELY(!sax->start_array(static_cast<std::size_t>(-1))))
12434 {
12435 return false;
12436 }
12437
12438 // closing ] -> we are done
12439 if (get_token() == token_type::end_array)
12440 {
12441 if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
12442 {
12443 return false;
12444 }
12445 break;
12446 }
12447
12448 // remember we are now inside an array
12449 states.push_back(true);
12450
12451 // parse values (no need to call get_token)
12452 continue;
12453 }
12454
12455 case token_type::value_float:
12456 {
12457 const auto res = m_lexer.get_number_float();
12458
12459 if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res)))
12460 {
12461 return sax->parse_error(m_lexer.get_position(),
12462 m_lexer.get_token_string(),
12463 out_of_range::create(406, concat("number overflow parsing '", m_lexer.get_token_string(), '\''), nullptr));
12464 }
12465
12466 if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))
12467 {
12468 return false;
12469 }
12470
12471 break;
12472 }
12473
12474 case token_type::literal_false:
12475 {
12476 if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))
12477 {
12478 return false;
12479 }
12480 break;
12481 }
12482
12483 case token_type::literal_null:
12484 {
12485 if (JSON_HEDLEY_UNLIKELY(!sax->null()))
12486 {
12487 return false;
12488 }
12489 break;
12490 }
12491
12492 case token_type::literal_true:
12493 {
12494 if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))
12495 {
12496 return false;
12497 }
12498 break;
12499 }
12500
12501 case token_type::value_integer:
12502 {
12503 if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer())))
12504 {
12505 return false;
12506 }
12507 break;
12508 }
12509
12510 case token_type::value_string:
12511 {
12512 if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string())))
12513 {
12514 return false;
12515 }
12516 break;
12517 }
12518
12519 case token_type::value_unsigned:
12520 {
12521 if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned())))
12522 {
12523 return false;
12524 }
12525 break;
12526 }
12527
12528 case token_type::parse_error:
12529 {
12530 // using "uninitialized" to avoid "expected" message
12531 return sax->parse_error(m_lexer.get_position(),
12532 m_lexer.get_token_string(),
12533 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, "value"), nullptr));
12534 }
12535 case token_type::end_of_input:
12536 {
12537 if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))
12538 {
12539 return sax->parse_error(m_lexer.get_position(),
12540 m_lexer.get_token_string(),
12541 parse_error::create(101, m_lexer.get_position(),
12542 "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
12543 }
12544
12545 return sax->parse_error(m_lexer.get_position(),
12546 m_lexer.get_token_string(),
12547 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
12548 }
12549 case token_type::uninitialized:
12550 case token_type::end_array:
12551 case token_type::end_object:
12552 case token_type::name_separator:
12553 case token_type::value_separator:
12554 case token_type::literal_or_value:
12555 default: // the last token was unexpected
12556 {
12557 return sax->parse_error(m_lexer.get_position(),
12558 m_lexer.get_token_string(),
12559 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, "value"), nullptr));
12560 }
12561 }
12562 }
12563 else
12564 {
12565 skip_to_state_evaluation = false;
12566 }
12567
12568 // we reached this line after we successfully parsed a value
12569 if (states.empty())
12570 {
12571 // empty stack: we reached the end of the hierarchy: done
12572 return true;
12573 }
12574
12575 if (states.back()) // array
12576 {
12577 // comma -> next value
12578 if (get_token() == token_type::value_separator)
12579 {
12580 // parse a new value
12581 get_token();
12582 continue;
12583 }
12584
12585 // closing ]
12586 if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))
12587 {
12588 if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))
12589 {
12590 return false;
12591 }
12592
12593 // We are done with this array. Before we can parse a
12594 // new value, we need to evaluate the new state first.
12595 // By setting skip_to_state_evaluation to false, we
12596 // are effectively jumping to the beginning of this if.
12597 JSON_ASSERT(!states.empty());
12598 states.pop_back();
12599 skip_to_state_evaluation = true;
12600 continue;
12601 }
12602
12603 return sax->parse_error(m_lexer.get_position(),
12604 m_lexer.get_token_string(),
12605 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, "array"), nullptr));
12606 }
12607
12608 // states.back() is false -> object
12609
12610 // comma -> next value
12611 if (get_token() == token_type::value_separator)
12612 {
12613 // parse key
12614 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))
12615 {
12616 return sax->parse_error(m_lexer.get_position(),
12617 m_lexer.get_token_string(),
12618 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, "object key"), nullptr));
12619 }
12620
12621 if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))
12622 {
12623 return false;
12624 }
12625
12626 // parse separator (:)
12627 if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))
12628 {
12629 return sax->parse_error(m_lexer.get_position(),
12630 m_lexer.get_token_string(),
12631 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, "object separator"), nullptr));
12632 }
12633
12634 // parse values
12635 get_token();
12636 continue;
12637 }
12638
12639 // closing }
12640 if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))
12641 {
12642 if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))
12643 {
12644 return false;
12645 }
12646
12647 // We are done with this object. Before we can parse a
12648 // new value, we need to evaluate the new state first.
12649 // By setting skip_to_state_evaluation to false, we
12650 // are effectively jumping to the beginning of this if.
12651 JSON_ASSERT(!states.empty());
12652 states.pop_back();
12653 skip_to_state_evaluation = true;
12654 continue;
12655 }
12656
12657 return sax->parse_error(m_lexer.get_position(),
12658 m_lexer.get_token_string(),
12659 parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, "object"), nullptr));
12660 }
12661 }
12662
12664 token_type get_token()
12665 {
12666 return last_token = m_lexer.scan();
12667 }
12668
12669 std::string exception_message(const token_type expected, const std::string& context)
12670 {
12671 std::string error_msg = "syntax error ";
12672
12673 if (!context.empty())
12674 {
12675 error_msg += concat("while parsing ", context, ' ');
12676 }
12677
12678 error_msg += "- ";
12679
12680 if (last_token == token_type::parse_error)
12681 {
12682 error_msg += concat(m_lexer.get_error_message(), "; last read: '",
12683 m_lexer.get_token_string(), '\'');
12684 }
12685 else
12686 {
12687 error_msg += concat("unexpected ", lexer_t::token_type_name(last_token));
12688 }
12689
12690 if (expected != token_type::uninitialized)
12691 {
12692 error_msg += concat("; expected ", lexer_t::token_type_name(expected));
12693 }
12694
12695 return error_msg;
12696 }
12697
12698 private:
12700 const parser_callback_t<BasicJsonType> callback = nullptr;
12702 token_type last_token = token_type::uninitialized;
12704 lexer_t m_lexer;
12706 const bool allow_exceptions = true;
12707};
12708
12709} // namespace detail
12710NLOHMANN_JSON_NAMESPACE_END
12711
12712// #include <nlohmann/detail/iterators/internal_iterator.hpp>
12713// __ _____ _____ _____
12714// __| | __| | | | JSON for Modern C++
12715// | | |__ | | | | | | version 3.11.3
12716// |_____|_____|_____|_|___| https://github.com/nlohmann/json
12717//
12718// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
12719// SPDX-License-Identifier: MIT
12720
12721
12722
12723// #include <nlohmann/detail/abi_macros.hpp>
12724
12725// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
12726// __ _____ _____ _____
12727// __| | __| | | | JSON for Modern C++
12728// | | |__ | | | | | | version 3.11.3
12729// |_____|_____|_____|_|___| https://github.com/nlohmann/json
12730//
12731// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
12732// SPDX-License-Identifier: MIT
12733
12734
12735
12736#include <cstddef> // ptrdiff_t
12737#include <limits> // numeric_limits
12738
12739// #include <nlohmann/detail/macro_scope.hpp>
12740
12741
12742NLOHMANN_JSON_NAMESPACE_BEGIN
12743namespace detail
12744{
12745
12746/*
12747@brief an iterator for primitive JSON types
12748
12749This class models an iterator for primitive JSON types (boolean, number,
12750string). It's only purpose is to allow the iterator/const_iterator classes
12751to "iterate" over primitive values. Internally, the iterator is modeled by
12752a `difference_type` variable. Value begin_value (`0`) models the begin,
12753end_value (`1`) models past the end.
12754*/
12756{
12757 private:
12758 using difference_type = std::ptrdiff_t;
12759 static constexpr difference_type begin_value = 0;
12760 static constexpr difference_type end_value = begin_value + 1;
12761
12762 JSON_PRIVATE_UNLESS_TESTED:
12764 difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();
12765
12766 public:
12767 constexpr difference_type get_value() const noexcept
12768 {
12769 return m_it;
12770 }
12771
12773 void set_begin() noexcept
12774 {
12775 m_it = begin_value;
12776 }
12777
12779 void set_end() noexcept
12780 {
12781 m_it = end_value;
12782 }
12783
12785 constexpr bool is_begin() const noexcept
12786 {
12787 return m_it == begin_value;
12788 }
12789
12791 constexpr bool is_end() const noexcept
12792 {
12793 return m_it == end_value;
12794 }
12795
12796 friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
12797 {
12798 return lhs.m_it == rhs.m_it;
12799 }
12800
12801 friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
12802 {
12803 return lhs.m_it < rhs.m_it;
12804 }
12805
12806 primitive_iterator_t operator+(difference_type n) noexcept
12807 {
12808 auto result = *this;
12809 result += n;
12810 return result;
12811 }
12812
12813 friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept
12814 {
12815 return lhs.m_it - rhs.m_it;
12816 }
12817
12818 primitive_iterator_t& operator++() noexcept
12819 {
12820 ++m_it;
12821 return *this;
12822 }
12823
12824 primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp)
12825 {
12826 auto result = *this;
12827 ++m_it;
12828 return result;
12829 }
12830
12831 primitive_iterator_t& operator--() noexcept
12832 {
12833 --m_it;
12834 return *this;
12835 }
12836
12837 primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp)
12838 {
12839 auto result = *this;
12840 --m_it;
12841 return result;
12842 }
12843
12844 primitive_iterator_t& operator+=(difference_type n) noexcept
12845 {
12846 m_it += n;
12847 return *this;
12848 }
12849
12850 primitive_iterator_t& operator-=(difference_type n) noexcept
12851 {
12852 m_it -= n;
12853 return *this;
12854 }
12855};
12856
12857} // namespace detail
12858NLOHMANN_JSON_NAMESPACE_END
12859
12860
12861NLOHMANN_JSON_NAMESPACE_BEGIN
12862namespace detail
12863{
12864
12871template<typename BasicJsonType> struct internal_iterator
12872{
12874 typename BasicJsonType::object_t::iterator object_iterator {};
12876 typename BasicJsonType::array_t::iterator array_iterator {};
12878 primitive_iterator_t primitive_iterator {};
12879};
12880
12881} // namespace detail
12882NLOHMANN_JSON_NAMESPACE_END
12883
12884// #include <nlohmann/detail/iterators/iter_impl.hpp>
12885// __ _____ _____ _____
12886// __| | __| | | | JSON for Modern C++
12887// | | |__ | | | | | | version 3.11.3
12888// |_____|_____|_____|_|___| https://github.com/nlohmann/json
12889//
12890// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
12891// SPDX-License-Identifier: MIT
12892
12893
12894
12895#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
12896#include <type_traits> // conditional, is_const, remove_const
12897
12898// #include <nlohmann/detail/exceptions.hpp>
12899
12900// #include <nlohmann/detail/iterators/internal_iterator.hpp>
12901
12902// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
12903
12904// #include <nlohmann/detail/macro_scope.hpp>
12905
12906// #include <nlohmann/detail/meta/cpp_future.hpp>
12907
12908// #include <nlohmann/detail/meta/type_traits.hpp>
12909
12910// #include <nlohmann/detail/value_t.hpp>
12911
12912
12913NLOHMANN_JSON_NAMESPACE_BEGIN
12914namespace detail
12915{
12916
12917// forward declare, to be able to friend it later on
12918template<typename IteratorType> class iteration_proxy;
12919template<typename IteratorType> class iteration_proxy_value;
12920
12937template<typename BasicJsonType>
12938class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
12939{
12941 using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
12944 friend BasicJsonType;
12947
12948 using object_t = typename BasicJsonType::object_t;
12949 using array_t = typename BasicJsonType::array_t;
12950 // make sure BasicJsonType is basic_json or const basic_json
12952 "iter_impl only accepts (const) basic_json");
12953 // superficial check for the LegacyBidirectionalIterator named requirement
12954 static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value
12955 && std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
12956 "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.");
12957
12958 public:
12964 using iterator_category = std::bidirectional_iterator_tag;
12965
12967 using value_type = typename BasicJsonType::value_type;
12969 using difference_type = typename BasicJsonType::difference_type;
12971 using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
12972 typename BasicJsonType::const_pointer,
12973 typename BasicJsonType::pointer>::type;
12976 typename std::conditional<std::is_const<BasicJsonType>::value,
12977 typename BasicJsonType::const_reference,
12978 typename BasicJsonType::reference>::type;
12979
12980 iter_impl() = default;
12981 ~iter_impl() = default;
12982 iter_impl(iter_impl&&) noexcept = default;
12983 iter_impl& operator=(iter_impl&&) noexcept = default;
12984
12991 explicit iter_impl(pointer object) noexcept : m_object(object)
12992 {
12993 JSON_ASSERT(m_object != nullptr);
12994
12995 switch (m_object->m_data.m_type)
12996 {
12997 case value_t::object:
12998 {
12999 m_it.object_iterator = typename object_t::iterator();
13000 break;
13001 }
13002
13003 case value_t::array:
13004 {
13005 m_it.array_iterator = typename array_t::iterator();
13006 break;
13007 }
13008
13009 case value_t::null:
13010 case value_t::string:
13011 case value_t::boolean:
13012 case value_t::number_integer:
13013 case value_t::number_unsigned:
13014 case value_t::number_float:
13015 case value_t::binary:
13016 case value_t::discarded:
13017 default:
13018 {
13019 m_it.primitive_iterator = primitive_iterator_t();
13020 break;
13021 }
13022 }
13023 }
13024
13042 : m_object(other.m_object), m_it(other.m_it)
13043 {}
13044
13052 {
13053 if (&other != this)
13054 {
13055 m_object = other.m_object;
13056 m_it = other.m_it;
13057 }
13058 return *this;
13059 }
13060
13066 iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
13067 : m_object(other.m_object), m_it(other.m_it)
13068 {}
13069
13076 iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp)
13077 {
13078 m_object = other.m_object;
13079 m_it = other.m_it;
13080 return *this;
13081 }
13082
13083 JSON_PRIVATE_UNLESS_TESTED:
13088 void set_begin() noexcept
13089 {
13090 JSON_ASSERT(m_object != nullptr);
13091
13092 switch (m_object->m_data.m_type)
13093 {
13094 case value_t::object:
13095 {
13096 m_it.object_iterator = m_object->m_data.m_value.object->begin();
13097 break;
13098 }
13099
13100 case value_t::array:
13101 {
13102 m_it.array_iterator = m_object->m_data.m_value.array->begin();
13103 break;
13104 }
13105
13106 case value_t::null:
13107 {
13108 // set to end so begin()==end() is true: null is empty
13109 m_it.primitive_iterator.set_end();
13110 break;
13111 }
13112
13113 case value_t::string:
13114 case value_t::boolean:
13115 case value_t::number_integer:
13116 case value_t::number_unsigned:
13117 case value_t::number_float:
13118 case value_t::binary:
13119 case value_t::discarded:
13120 default:
13121 {
13122 m_it.primitive_iterator.set_begin();
13123 break;
13124 }
13125 }
13126 }
13127
13132 void set_end() noexcept
13133 {
13134 JSON_ASSERT(m_object != nullptr);
13135
13136 switch (m_object->m_data.m_type)
13137 {
13138 case value_t::object:
13139 {
13140 m_it.object_iterator = m_object->m_data.m_value.object->end();
13141 break;
13142 }
13143
13144 case value_t::array:
13145 {
13146 m_it.array_iterator = m_object->m_data.m_value.array->end();
13147 break;
13148 }
13149
13150 case value_t::null:
13151 case value_t::string:
13152 case value_t::boolean:
13153 case value_t::number_integer:
13154 case value_t::number_unsigned:
13155 case value_t::number_float:
13156 case value_t::binary:
13157 case value_t::discarded:
13158 default:
13159 {
13160 m_it.primitive_iterator.set_end();
13161 break;
13162 }
13163 }
13164 }
13165
13166 public:
13172 {
13173 JSON_ASSERT(m_object != nullptr);
13174
13175 switch (m_object->m_data.m_type)
13176 {
13177 case value_t::object:
13178 {
13179 JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
13180 return m_it.object_iterator->second;
13181 }
13182
13183 case value_t::array:
13184 {
13185 JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
13186 return *m_it.array_iterator;
13187 }
13188
13189 case value_t::null:
13190 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
13191
13192 case value_t::string:
13193 case value_t::boolean:
13194 case value_t::number_integer:
13195 case value_t::number_unsigned:
13196 case value_t::number_float:
13197 case value_t::binary:
13198 case value_t::discarded:
13199 default:
13200 {
13201 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
13202 {
13203 return *m_object;
13204 }
13205
13206 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
13207 }
13208 }
13209 }
13210
13216 {
13217 JSON_ASSERT(m_object != nullptr);
13218
13219 switch (m_object->m_data.m_type)
13220 {
13221 case value_t::object:
13222 {
13223 JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());
13224 return &(m_it.object_iterator->second);
13225 }
13226
13227 case value_t::array:
13228 {
13229 JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());
13230 return &*m_it.array_iterator;
13231 }
13232
13233 case value_t::null:
13234 case value_t::string:
13235 case value_t::boolean:
13236 case value_t::number_integer:
13237 case value_t::number_unsigned:
13238 case value_t::number_float:
13239 case value_t::binary:
13240 case value_t::discarded:
13241 default:
13242 {
13243 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))
13244 {
13245 return m_object;
13246 }
13247
13248 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
13249 }
13250 }
13251 }
13252
13257 iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp)
13258 {
13259 auto result = *this;
13260 ++(*this);
13261 return result;
13262 }
13263
13269 {
13270 JSON_ASSERT(m_object != nullptr);
13271
13272 switch (m_object->m_data.m_type)
13273 {
13274 case value_t::object:
13275 {
13276 std::advance(m_it.object_iterator, 1);
13277 break;
13278 }
13279
13280 case value_t::array:
13281 {
13282 std::advance(m_it.array_iterator, 1);
13283 break;
13284 }
13285
13286 case value_t::null:
13287 case value_t::string:
13288 case value_t::boolean:
13289 case value_t::number_integer:
13290 case value_t::number_unsigned:
13291 case value_t::number_float:
13292 case value_t::binary:
13293 case value_t::discarded:
13294 default:
13295 {
13296 ++m_it.primitive_iterator;
13297 break;
13298 }
13299 }
13300
13301 return *this;
13302 }
13303
13308 iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp)
13309 {
13310 auto result = *this;
13311 --(*this);
13312 return result;
13313 }
13314
13320 {
13321 JSON_ASSERT(m_object != nullptr);
13322
13323 switch (m_object->m_data.m_type)
13324 {
13325 case value_t::object:
13326 {
13327 std::advance(m_it.object_iterator, -1);
13328 break;
13329 }
13330
13331 case value_t::array:
13332 {
13333 std::advance(m_it.array_iterator, -1);
13334 break;
13335 }
13336
13337 case value_t::null:
13338 case value_t::string:
13339 case value_t::boolean:
13340 case value_t::number_integer:
13341 case value_t::number_unsigned:
13342 case value_t::number_float:
13343 case value_t::binary:
13344 case value_t::discarded:
13345 default:
13346 {
13347 --m_it.primitive_iterator;
13348 break;
13349 }
13350 }
13351
13352 return *this;
13353 }
13354
13359 template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
13360 bool operator==(const IterImpl& other) const
13361 {
13362 // if objects are not the same, the comparison is undefined
13363 if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
13364 {
13365 JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
13366 }
13367
13368 JSON_ASSERT(m_object != nullptr);
13369
13370 switch (m_object->m_data.m_type)
13371 {
13372 case value_t::object:
13373 return (m_it.object_iterator == other.m_it.object_iterator);
13374
13375 case value_t::array:
13376 return (m_it.array_iterator == other.m_it.array_iterator);
13377
13378 case value_t::null:
13379 case value_t::string:
13380 case value_t::boolean:
13381 case value_t::number_integer:
13382 case value_t::number_unsigned:
13383 case value_t::number_float:
13384 case value_t::binary:
13385 case value_t::discarded:
13386 default:
13387 return (m_it.primitive_iterator == other.m_it.primitive_iterator);
13388 }
13389 }
13390
13395 template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >
13396 bool operator!=(const IterImpl& other) const
13397 {
13398 return !operator==(other);
13399 }
13400
13405 bool operator<(const iter_impl& other) const
13406 {
13407 // if objects are not the same, the comparison is undefined
13408 if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))
13409 {
13410 JSON_THROW(invalid_iterator::create(212, "cannot compare iterators of different containers", m_object));
13411 }
13412
13413 JSON_ASSERT(m_object != nullptr);
13414
13415 switch (m_object->m_data.m_type)
13416 {
13417 case value_t::object:
13418 JSON_THROW(invalid_iterator::create(213, "cannot compare order of object iterators", m_object));
13419
13420 case value_t::array:
13421 return (m_it.array_iterator < other.m_it.array_iterator);
13422
13423 case value_t::null:
13424 case value_t::string:
13425 case value_t::boolean:
13426 case value_t::number_integer:
13427 case value_t::number_unsigned:
13428 case value_t::number_float:
13429 case value_t::binary:
13430 case value_t::discarded:
13431 default:
13432 return (m_it.primitive_iterator < other.m_it.primitive_iterator);
13433 }
13434 }
13435
13440 bool operator<=(const iter_impl& other) const
13441 {
13442 return !other.operator < (*this);
13443 }
13444
13449 bool operator>(const iter_impl& other) const
13450 {
13451 return !operator<=(other);
13452 }
13453
13458 bool operator>=(const iter_impl& other) const
13459 {
13460 return !operator<(other);
13461 }
13462
13468 {
13469 JSON_ASSERT(m_object != nullptr);
13470
13471 switch (m_object->m_data.m_type)
13472 {
13473 case value_t::object:
13474 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
13475
13476 case value_t::array:
13477 {
13478 std::advance(m_it.array_iterator, i);
13479 break;
13480 }
13481
13482 case value_t::null:
13483 case value_t::string:
13484 case value_t::boolean:
13485 case value_t::number_integer:
13486 case value_t::number_unsigned:
13487 case value_t::number_float:
13488 case value_t::binary:
13489 case value_t::discarded:
13490 default:
13491 {
13492 m_it.primitive_iterator += i;
13493 break;
13494 }
13495 }
13496
13497 return *this;
13498 }
13499
13505 {
13506 return operator+=(-i);
13507 }
13508
13514 {
13515 auto result = *this;
13516 result += i;
13517 return result;
13518 }
13519
13525 {
13526 auto result = it;
13527 result += i;
13528 return result;
13529 }
13530
13536 {
13537 auto result = *this;
13538 result -= i;
13539 return result;
13540 }
13541
13547 {
13548 JSON_ASSERT(m_object != nullptr);
13549
13550 switch (m_object->m_data.m_type)
13551 {
13552 case value_t::object:
13553 JSON_THROW(invalid_iterator::create(209, "cannot use offsets with object iterators", m_object));
13554
13555 case value_t::array:
13556 return m_it.array_iterator - other.m_it.array_iterator;
13557
13558 case value_t::null:
13559 case value_t::string:
13560 case value_t::boolean:
13561 case value_t::number_integer:
13562 case value_t::number_unsigned:
13563 case value_t::number_float:
13564 case value_t::binary:
13565 case value_t::discarded:
13566 default:
13567 return m_it.primitive_iterator - other.m_it.primitive_iterator;
13568 }
13569 }
13570
13576 {
13577 JSON_ASSERT(m_object != nullptr);
13578
13579 switch (m_object->m_data.m_type)
13580 {
13581 case value_t::object:
13582 JSON_THROW(invalid_iterator::create(208, "cannot use operator[] for object iterators", m_object));
13583
13584 case value_t::array:
13585 return *std::next(m_it.array_iterator, n);
13586
13587 case value_t::null:
13588 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
13589
13590 case value_t::string:
13591 case value_t::boolean:
13592 case value_t::number_integer:
13593 case value_t::number_unsigned:
13594 case value_t::number_float:
13595 case value_t::binary:
13596 case value_t::discarded:
13597 default:
13598 {
13599 if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))
13600 {
13601 return *m_object;
13602 }
13603
13604 JSON_THROW(invalid_iterator::create(214, "cannot get value", m_object));
13605 }
13606 }
13607 }
13608
13613 const typename object_t::key_type& key() const
13614 {
13615 JSON_ASSERT(m_object != nullptr);
13616
13617 if (JSON_HEDLEY_LIKELY(m_object->is_object()))
13618 {
13619 return m_it.object_iterator->first;
13620 }
13621
13622 JSON_THROW(invalid_iterator::create(207, "cannot use key() for non-object iterators", m_object));
13623 }
13624
13630 {
13631 return operator*();
13632 }
13633
13634 JSON_PRIVATE_UNLESS_TESTED:
13636 pointer m_object = nullptr;
13639};
13640
13641} // namespace detail
13642NLOHMANN_JSON_NAMESPACE_END
13643
13644// #include <nlohmann/detail/iterators/iteration_proxy.hpp>
13645
13646// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
13647// __ _____ _____ _____
13648// __| | __| | | | JSON for Modern C++
13649// | | |__ | | | | | | version 3.11.3
13650// |_____|_____|_____|_|___| https://github.com/nlohmann/json
13651//
13652// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
13653// SPDX-License-Identifier: MIT
13654
13655
13656
13657#include <cstddef> // ptrdiff_t
13658#include <iterator> // reverse_iterator
13659#include <utility> // declval
13660
13661// #include <nlohmann/detail/abi_macros.hpp>
13662
13663
13664NLOHMANN_JSON_NAMESPACE_BEGIN
13665namespace detail
13666{
13667
13669// reverse_iterator //
13671
13690template<typename Base>
13691class json_reverse_iterator : public std::reverse_iterator<Base>
13692{
13693 public:
13694 using difference_type = std::ptrdiff_t;
13696 using base_iterator = std::reverse_iterator<Base>;
13698 using reference = typename Base::reference;
13699
13701 explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
13702 : base_iterator(it) {}
13703
13705 explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
13706
13708 json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp)
13709 {
13710 return static_cast<json_reverse_iterator>(base_iterator::operator++(1));
13711 }
13712
13715 {
13716 return static_cast<json_reverse_iterator&>(base_iterator::operator++());
13717 }
13718
13720 json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp)
13721 {
13722 return static_cast<json_reverse_iterator>(base_iterator::operator--(1));
13723 }
13724
13727 {
13728 return static_cast<json_reverse_iterator&>(base_iterator::operator--());
13729 }
13730
13733 {
13734 return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));
13735 }
13736
13738 json_reverse_iterator operator+(difference_type i) const
13739 {
13740 return static_cast<json_reverse_iterator>(base_iterator::operator+(i));
13741 }
13742
13744 json_reverse_iterator operator-(difference_type i) const
13745 {
13746 return static_cast<json_reverse_iterator>(base_iterator::operator-(i));
13747 }
13748
13750 difference_type operator-(const json_reverse_iterator& other) const
13751 {
13752 return base_iterator(*this) - base_iterator(other);
13753 }
13754
13756 reference operator[](difference_type n) const
13757 {
13758 return *(this->operator+(n));
13759 }
13760
13762 auto key() const -> decltype(std::declval<Base>().key())
13763 {
13764 auto it = --this->base();
13765 return it.key();
13766 }
13767
13770 {
13771 auto it = --this->base();
13772 return it.operator * ();
13773 }
13774};
13775
13776} // namespace detail
13777NLOHMANN_JSON_NAMESPACE_END
13778
13779// #include <nlohmann/detail/iterators/primitive_iterator.hpp>
13780
13781// #include <nlohmann/detail/json_custom_base_class.hpp>
13782// __ _____ _____ _____
13783// __| | __| | | | JSON for Modern C++
13784// | | |__ | | | | | | version 3.11.3
13785// |_____|_____|_____|_|___| https://github.com/nlohmann/json
13786//
13787// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
13788// SPDX-License-Identifier: MIT
13789
13790
13791
13792#include <type_traits> // conditional, is_same
13793
13794// #include <nlohmann/detail/abi_macros.hpp>
13795
13796
13797NLOHMANN_JSON_NAMESPACE_BEGIN
13798namespace detail
13799{
13800
13812
13813template<class T>
13814using json_base_class = typename std::conditional <
13815 std::is_same<T, void>::value,
13817 T
13818 >::type;
13819
13820} // namespace detail
13821NLOHMANN_JSON_NAMESPACE_END
13822
13823// #include <nlohmann/detail/json_pointer.hpp>
13824// __ _____ _____ _____
13825// __| | __| | | | JSON for Modern C++
13826// | | |__ | | | | | | version 3.11.3
13827// |_____|_____|_____|_|___| https://github.com/nlohmann/json
13828//
13829// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
13830// SPDX-License-Identifier: MIT
13831
13832
13833
13834#include <algorithm> // all_of
13835#include <cctype> // isdigit
13836#include <cerrno> // errno, ERANGE
13837#include <cstdlib> // strtoull
13838#ifndef JSON_NO_IO
13839 #include <iosfwd> // ostream
13840#endif // JSON_NO_IO
13841#include <limits> // max
13842#include <numeric> // accumulate
13843#include <string> // string
13844#include <utility> // move
13845#include <vector> // vector
13846
13847// #include <nlohmann/detail/exceptions.hpp>
13848
13849// #include <nlohmann/detail/macro_scope.hpp>
13850
13851// #include <nlohmann/detail/string_concat.hpp>
13852
13853// #include <nlohmann/detail/string_escape.hpp>
13854
13855// #include <nlohmann/detail/value_t.hpp>
13856
13857
13858NLOHMANN_JSON_NAMESPACE_BEGIN
13859
13862template<typename RefStringType>
13864{
13865 // allow basic_json to access private members
13866 NLOHMANN_BASIC_JSON_TPL_DECLARATION
13867 friend class basic_json;
13868
13869 template<typename>
13870 friend class json_pointer;
13871
13872 template<typename T>
13874 {
13875 using type = T;
13876 };
13877
13878 NLOHMANN_BASIC_JSON_TPL_DECLARATION
13879 struct string_t_helper<NLOHMANN_BASIC_JSON_TPL>
13880 {
13881 using type = StringType;
13882 };
13883
13884 public:
13885 // for backwards compatibility accept BasicJsonType
13886 using string_t = typename string_t_helper<RefStringType>::type;
13887
13890 explicit json_pointer(const string_t& s = "")
13891 : reference_tokens(split(s))
13892 {}
13893
13896 string_t to_string() const
13897 {
13898 return std::accumulate(reference_tokens.begin(), reference_tokens.end(),
13899 string_t{},
13900 [](const string_t& a, const string_t& b)
13901 {
13902 return detail::concat(a, '/', detail::escape(b));
13903 });
13904 }
13905
13908 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())
13909 operator string_t() const
13910 {
13911 return to_string();
13912 }
13913
13914#ifndef JSON_NO_IO
13917 friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr)
13918 {
13919 o << ptr.to_string();
13920 return o;
13921 }
13922#endif
13923
13927 {
13928 reference_tokens.insert(reference_tokens.end(),
13929 ptr.reference_tokens.begin(),
13930 ptr.reference_tokens.end());
13931 return *this;
13932 }
13933
13936 json_pointer& operator/=(string_t token)
13937 {
13938 push_back(std::move(token));
13939 return *this;
13940 }
13941
13944 json_pointer& operator/=(std::size_t array_idx)
13945 {
13946 return *this /= std::to_string(array_idx);
13947 }
13948
13952 const json_pointer& rhs)
13953 {
13954 return json_pointer(lhs) /= rhs;
13955 }
13956
13959 friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param)
13960 {
13961 return json_pointer(lhs) /= std::move(token);
13962 }
13963
13966 friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx)
13967 {
13968 return json_pointer(lhs) /= array_idx;
13969 }
13970
13974 {
13975 if (empty())
13976 {
13977 return *this;
13978 }
13979
13980 json_pointer res = *this;
13981 res.pop_back();
13982 return res;
13983 }
13984
13988 {
13989 if (JSON_HEDLEY_UNLIKELY(empty()))
13990 {
13991 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
13992 }
13993
13994 reference_tokens.pop_back();
13995 }
13996
13999 const string_t& back() const
14000 {
14001 if (JSON_HEDLEY_UNLIKELY(empty()))
14002 {
14003 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
14004 }
14005
14006 return reference_tokens.back();
14007 }
14008
14011 void push_back(const string_t& token)
14012 {
14013 reference_tokens.push_back(token);
14014 }
14015
14018 void push_back(string_t&& token)
14019 {
14020 reference_tokens.push_back(std::move(token));
14021 }
14022
14025 bool empty() const noexcept
14026 {
14027 return reference_tokens.empty();
14028 }
14029
14030 private:
14041 template<typename BasicJsonType>
14042 static typename BasicJsonType::size_type array_index(const string_t& s)
14043 {
14044 using size_type = typename BasicJsonType::size_type;
14045
14046 // error condition (cf. RFC 6901, Sect. 4)
14047 if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))
14048 {
14049 JSON_THROW(detail::parse_error::create(106, 0, detail::concat("array index '", s, "' must not begin with '0'"), nullptr));
14050 }
14051
14052 // error condition (cf. RFC 6901, Sect. 4)
14053 if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))
14054 {
14055 JSON_THROW(detail::parse_error::create(109, 0, detail::concat("array index '", s, "' is not a number"), nullptr));
14056 }
14057
14058 const char* p = s.c_str();
14059 char* p_end = nullptr;
14060 errno = 0; // strtoull doesn't reset errno
14061 const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
14062 if (p == p_end // invalid input or empty string
14063 || errno == ERANGE // out of range
14064 || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read
14065 {
14066 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
14067 }
14068
14069 // only triggered on special platforms (like 32bit), see also
14070 // https://github.com/nlohmann/json/pull/2203
14071 if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int)
14072 {
14073 JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE
14074 }
14075
14076 return static_cast<size_type>(res);
14077 }
14078
14079 JSON_PRIVATE_UNLESS_TESTED:
14080 json_pointer top() const
14081 {
14082 if (JSON_HEDLEY_UNLIKELY(empty()))
14083 {
14084 JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent", nullptr));
14085 }
14086
14087 json_pointer result = *this;
14088 result.reference_tokens = {reference_tokens[0]};
14089 return result;
14090 }
14091
14092 private:
14101 template<typename BasicJsonType>
14102 BasicJsonType& get_and_create(BasicJsonType& j) const
14103 {
14104 auto* result = &j;
14105
14106 // in case no reference tokens exist, return a reference to the JSON value
14107 // j which will be overwritten by a primitive value
14108 for (const auto& reference_token : reference_tokens)
14109 {
14110 switch (result->type())
14111 {
14113 {
14114 if (reference_token == "0")
14115 {
14116 // start a new array if reference token is 0
14117 result = &result->operator[](0);
14118 }
14119 else
14120 {
14121 // start a new object otherwise
14122 result = &result->operator[](reference_token);
14123 }
14124 break;
14125 }
14126
14128 {
14129 // create an entry in the object
14130 result = &result->operator[](reference_token);
14131 break;
14132 }
14133
14135 {
14136 // create an entry in the array
14137 result = &result->operator[](array_index<BasicJsonType>(reference_token));
14138 break;
14139 }
14140
14141 /*
14142 The following code is only reached if there exists a reference
14143 token _and_ the current value is primitive. In this case, we have
14144 an error situation, because primitive values may only occur as
14145 single value; that is, with an empty list of reference tokens.
14146 */
14154 default:
14155 JSON_THROW(detail::type_error::create(313, "invalid value to unflatten", &j));
14156 }
14157 }
14158
14159 return *result;
14160 }
14161
14181 template<typename BasicJsonType>
14182 BasicJsonType& get_unchecked(BasicJsonType* ptr) const
14183 {
14184 for (const auto& reference_token : reference_tokens)
14185 {
14186 // convert null values to arrays or objects before continuing
14187 if (ptr->is_null())
14188 {
14189 // check if reference token is a number
14190 const bool nums =
14191 std::all_of(reference_token.begin(), reference_token.end(),
14192 [](const unsigned char x)
14193 {
14194 return std::isdigit(x);
14195 });
14196
14197 // change value to array for numbers or "-" or to object otherwise
14198 *ptr = (nums || reference_token == "-")
14201 }
14202
14203 switch (ptr->type())
14204 {
14206 {
14207 // use unchecked object access
14208 ptr = &ptr->operator[](reference_token);
14209 break;
14210 }
14211
14213 {
14214 if (reference_token == "-")
14215 {
14216 // explicitly treat "-" as index beyond the end
14217 ptr = &ptr->operator[](ptr->m_data.m_value.array->size());
14218 }
14219 else
14220 {
14221 // convert array index to number; unchecked access
14222 ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
14223 }
14224 break;
14225 }
14226
14235 default:
14236 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
14237 }
14238 }
14239
14240 return *ptr;
14241 }
14242
14249 template<typename BasicJsonType>
14250 BasicJsonType& get_checked(BasicJsonType* ptr) const
14251 {
14252 for (const auto& reference_token : reference_tokens)
14253 {
14254 switch (ptr->type())
14255 {
14257 {
14258 // note: at performs range check
14259 ptr = &ptr->at(reference_token);
14260 break;
14261 }
14262
14264 {
14265 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
14266 {
14267 // "-" always fails the range check
14268 JSON_THROW(detail::out_of_range::create(402, detail::concat(
14269 "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
14270 ") is out of range"), ptr));
14271 }
14272
14273 // note: at performs range check
14274 ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
14275 break;
14276 }
14277
14286 default:
14287 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
14288 }
14289 }
14290
14291 return *ptr;
14292 }
14293
14307 template<typename BasicJsonType>
14308 const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const
14309 {
14310 for (const auto& reference_token : reference_tokens)
14311 {
14312 switch (ptr->type())
14313 {
14315 {
14316 // use unchecked object access
14317 ptr = &ptr->operator[](reference_token);
14318 break;
14319 }
14320
14322 {
14323 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
14324 {
14325 // "-" cannot be used for const access
14326 JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr));
14327 }
14328
14329 // use unchecked array access
14330 ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));
14331 break;
14332 }
14333
14342 default:
14343 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
14344 }
14345 }
14346
14347 return *ptr;
14348 }
14349
14356 template<typename BasicJsonType>
14357 const BasicJsonType& get_checked(const BasicJsonType* ptr) const
14358 {
14359 for (const auto& reference_token : reference_tokens)
14360 {
14361 switch (ptr->type())
14362 {
14364 {
14365 // note: at performs range check
14366 ptr = &ptr->at(reference_token);
14367 break;
14368 }
14369
14371 {
14372 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
14373 {
14374 // "-" always fails the range check
14375 JSON_THROW(detail::out_of_range::create(402, detail::concat(
14376 "array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
14377 ") is out of range"), ptr));
14378 }
14379
14380 // note: at performs range check
14381 ptr = &ptr->at(array_index<BasicJsonType>(reference_token));
14382 break;
14383 }
14384
14393 default:
14394 JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", reference_token, "'"), ptr));
14395 }
14396 }
14397
14398 return *ptr;
14399 }
14400
14405 template<typename BasicJsonType>
14406 bool contains(const BasicJsonType* ptr) const
14407 {
14408 for (const auto& reference_token : reference_tokens)
14409 {
14410 switch (ptr->type())
14411 {
14413 {
14414 if (!ptr->contains(reference_token))
14415 {
14416 // we did not find the key in the object
14417 return false;
14418 }
14419
14420 ptr = &ptr->operator[](reference_token);
14421 break;
14422 }
14423
14425 {
14426 if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
14427 {
14428 // "-" always fails the range check
14429 return false;
14430 }
14431 if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !("0" <= reference_token && reference_token <= "9")))
14432 {
14433 // invalid char
14434 return false;
14435 }
14436 if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))
14437 {
14438 if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))
14439 {
14440 // first char should be between '1' and '9'
14441 return false;
14442 }
14443 for (std::size_t i = 1; i < reference_token.size(); i++)
14444 {
14445 if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))
14446 {
14447 // other char should be between '0' and '9'
14448 return false;
14449 }
14450 }
14451 }
14452
14453 const auto idx = array_index<BasicJsonType>(reference_token);
14454 if (idx >= ptr->size())
14455 {
14456 // index out of range
14457 return false;
14458 }
14459
14460 ptr = &ptr->operator[](idx);
14461 break;
14462 }
14463
14472 default:
14473 {
14474 // we do not expect primitive values if there is still a
14475 // reference token to process
14476 return false;
14477 }
14478 }
14479 }
14480
14481 // no reference token left means we found a primitive value
14482 return true;
14483 }
14484
14494 static std::vector<string_t> split(const string_t& reference_string)
14495 {
14496 std::vector<string_t> result;
14497
14498 // special case: empty reference string -> no reference tokens
14499 if (reference_string.empty())
14500 {
14501 return result;
14502 }
14503
14504 // check if nonempty reference string begins with slash
14505 if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))
14506 {
14507 JSON_THROW(detail::parse_error::create(107, 1, detail::concat("JSON pointer must be empty or begin with '/' - was: '", reference_string, "'"), nullptr));
14508 }
14509
14510 // extract the reference tokens:
14511 // - slash: position of the last read slash (or end of string)
14512 // - start: position after the previous slash
14513 for (
14514 // search for the first slash after the first character
14515 std::size_t slash = reference_string.find_first_of('/', 1),
14516 // set the beginning of the first reference token
14517 start = 1;
14518 // we can stop if start == 0 (if slash == string_t::npos)
14519 start != 0;
14520 // set the beginning of the next reference token
14521 // (will eventually be 0 if slash == string_t::npos)
14522 start = (slash == string_t::npos) ? 0 : slash + 1,
14523 // find next slash
14524 slash = reference_string.find_first_of('/', start))
14525 {
14526 // use the text between the beginning of the reference token
14527 // (start) and the last slash (slash).
14528 auto reference_token = reference_string.substr(start, slash - start);
14529
14530 // check reference tokens are properly escaped
14531 for (std::size_t pos = reference_token.find_first_of('~');
14532 pos != string_t::npos;
14533 pos = reference_token.find_first_of('~', pos + 1))
14534 {
14535 JSON_ASSERT(reference_token[pos] == '~');
14536
14537 // ~ must be followed by 0 or 1
14538 if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||
14539 (reference_token[pos + 1] != '0' &&
14540 reference_token[pos + 1] != '1')))
14541 {
14542 JSON_THROW(detail::parse_error::create(108, 0, "escape character '~' must be followed with '0' or '1'", nullptr));
14543 }
14544 }
14545
14546 // finally, store the reference token
14547 detail::unescape(reference_token);
14548 result.push_back(reference_token);
14549 }
14550
14551 return result;
14552 }
14553
14554 private:
14562 template<typename BasicJsonType>
14563 static void flatten(const string_t& reference_string,
14564 const BasicJsonType& value,
14565 BasicJsonType& result)
14566 {
14567 switch (value.type())
14568 {
14570 {
14571 if (value.m_data.m_value.array->empty())
14572 {
14573 // flatten empty array as null
14574 result[reference_string] = nullptr;
14575 }
14576 else
14577 {
14578 // iterate array and use index as reference string
14579 for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i)
14580 {
14581 flatten(detail::concat(reference_string, '/', std::to_string(i)),
14582 value.m_data.m_value.array->operator[](i), result);
14583 }
14584 }
14585 break;
14586 }
14587
14589 {
14590 if (value.m_data.m_value.object->empty())
14591 {
14592 // flatten empty object as null
14593 result[reference_string] = nullptr;
14594 }
14595 else
14596 {
14597 // iterate object and use keys as reference string
14598 for (const auto& element : *value.m_data.m_value.object)
14599 {
14600 flatten(detail::concat(reference_string, '/', detail::escape(element.first)), element.second, result);
14601 }
14602 }
14603 break;
14604 }
14605
14614 default:
14615 {
14616 // add primitive value with its reference string
14617 result[reference_string] = value;
14618 break;
14619 }
14620 }
14621 }
14622
14633 template<typename BasicJsonType>
14634 static BasicJsonType
14635 unflatten(const BasicJsonType& value)
14636 {
14637 if (JSON_HEDLEY_UNLIKELY(!value.is_object()))
14638 {
14639 JSON_THROW(detail::type_error::create(314, "only objects can be unflattened", &value));
14640 }
14641
14642 BasicJsonType result;
14643
14644 // iterate the JSON object values
14645 for (const auto& element : *value.m_data.m_value.object)
14646 {
14647 if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))
14648 {
14649 JSON_THROW(detail::type_error::create(315, "values in object must be primitive", &element.second));
14650 }
14651
14652 // assign value to reference pointed to by JSON pointer; Note that if
14653 // the JSON pointer is "" (i.e., points to the whole value), function
14654 // get_and_create returns a reference to result itself. An assignment
14655 // will then create a primitive value.
14656 json_pointer(element.first).get_and_create(result) = element.second;
14657 }
14658
14659 return result;
14660 }
14661
14662 // can't use conversion operator because of ambiguity
14663 json_pointer<string_t> convert() const&
14664 {
14666 result.reference_tokens = reference_tokens;
14667 return result;
14668 }
14669
14670 json_pointer<string_t> convert()&&
14671 {
14673 result.reference_tokens = std::move(reference_tokens);
14674 return result;
14675 }
14676
14677 public:
14678#if JSON_HAS_THREE_WAY_COMPARISON
14681 template<typename RefStringTypeRhs>
14682 bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept
14683 {
14684 return reference_tokens == rhs.reference_tokens;
14685 }
14686
14689 JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))
14690 bool operator==(const string_t& rhs) const
14691 {
14692 return *this == json_pointer(rhs);
14693 }
14694
14696 template<typename RefStringTypeRhs>
14697 std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD*
14698 {
14699 return reference_tokens <=> rhs.reference_tokens; // *NOPAD*
14700 }
14701#else
14704 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14705 // NOLINTNEXTLINE(readability-redundant-declaration)
14706 friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
14707 const json_pointer<RefStringTypeRhs>& rhs) noexcept;
14708
14711 template<typename RefStringTypeLhs, typename StringType>
14712 // NOLINTNEXTLINE(readability-redundant-declaration)
14713 friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
14714 const StringType& rhs);
14715
14718 template<typename RefStringTypeRhs, typename StringType>
14719 // NOLINTNEXTLINE(readability-redundant-declaration)
14720 friend bool operator==(const StringType& lhs,
14722
14725 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14726 // NOLINTNEXTLINE(readability-redundant-declaration)
14727 friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
14728 const json_pointer<RefStringTypeRhs>& rhs) noexcept;
14729
14732 template<typename RefStringTypeLhs, typename StringType>
14733 // NOLINTNEXTLINE(readability-redundant-declaration)
14734 friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
14735 const StringType& rhs);
14736
14739 template<typename RefStringTypeRhs, typename StringType>
14740 // NOLINTNEXTLINE(readability-redundant-declaration)
14741 friend bool operator!=(const StringType& lhs,
14743
14745 template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14746 // NOLINTNEXTLINE(readability-redundant-declaration)
14747 friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
14748 const json_pointer<RefStringTypeRhs>& rhs) noexcept;
14749#endif
14750
14751 private:
14753 std::vector<string_t> reference_tokens;
14754};
14755
14756#if !JSON_HAS_THREE_WAY_COMPARISON
14757// functions cannot be defined inside class due to ODR violations
14758template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14759inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
14760 const json_pointer<RefStringTypeRhs>& rhs) noexcept
14761{
14762 return lhs.reference_tokens == rhs.reference_tokens;
14763}
14764
14765template<typename RefStringTypeLhs,
14766 typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
14767JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
14768inline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,
14769 const StringType& rhs)
14770{
14771 return lhs == json_pointer<RefStringTypeLhs>(rhs);
14772}
14773
14774template<typename RefStringTypeRhs,
14775 typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
14776JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))
14777inline bool operator==(const StringType& lhs,
14778 const json_pointer<RefStringTypeRhs>& rhs)
14779{
14780 return json_pointer<RefStringTypeRhs>(lhs) == rhs;
14781}
14782
14783template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14784inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
14785 const json_pointer<RefStringTypeRhs>& rhs) noexcept
14786{
14787 return !(lhs == rhs);
14788}
14789
14790template<typename RefStringTypeLhs,
14791 typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>
14792JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
14793inline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,
14794 const StringType& rhs)
14795{
14796 return !(lhs == rhs);
14797}
14798
14799template<typename RefStringTypeRhs,
14800 typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>
14801JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))
14802inline bool operator!=(const StringType& lhs,
14803 const json_pointer<RefStringTypeRhs>& rhs)
14804{
14805 return !(lhs == rhs);
14806}
14807
14808template<typename RefStringTypeLhs, typename RefStringTypeRhs>
14809inline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,
14810 const json_pointer<RefStringTypeRhs>& rhs) noexcept
14811{
14812 return lhs.reference_tokens < rhs.reference_tokens;
14813}
14814#endif
14815
14816NLOHMANN_JSON_NAMESPACE_END
14817
14818// #include <nlohmann/detail/json_ref.hpp>
14819// __ _____ _____ _____
14820// __| | __| | | | JSON for Modern C++
14821// | | |__ | | | | | | version 3.11.3
14822// |_____|_____|_____|_|___| https://github.com/nlohmann/json
14823//
14824// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
14825// SPDX-License-Identifier: MIT
14826
14827
14828
14829#include <initializer_list>
14830#include <utility>
14831
14832// #include <nlohmann/detail/abi_macros.hpp>
14833
14834// #include <nlohmann/detail/meta/type_traits.hpp>
14835
14836
14837NLOHMANN_JSON_NAMESPACE_BEGIN
14838namespace detail
14839{
14840
14841template<typename BasicJsonType>
14843{
14844 public:
14845 using value_type = BasicJsonType;
14846
14847 json_ref(value_type&& value)
14848 : owned_value(std::move(value))
14849 {}
14850
14851 json_ref(const value_type& value)
14852 : value_ref(&value)
14853 {}
14854
14855 json_ref(std::initializer_list<json_ref> init)
14856 : owned_value(init)
14857 {}
14858
14859 template <
14860 class... Args,
14861 enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >
14862 json_ref(Args && ... args)
14863 : owned_value(std::forward<Args>(args)...)
14864 {}
14865
14866 // class should be movable only
14867 json_ref(json_ref&&) noexcept = default;
14868 json_ref(const json_ref&) = delete;
14869 json_ref& operator=(const json_ref&) = delete;
14870 json_ref& operator=(json_ref&&) = delete;
14871 ~json_ref() = default;
14872
14873 value_type moved_or_copied() const
14874 {
14875 if (value_ref == nullptr)
14876 {
14877 return std::move(owned_value);
14878 }
14879 return *value_ref;
14880 }
14881
14882 value_type const& operator*() const
14883 {
14884 return value_ref ? *value_ref : owned_value;
14885 }
14886
14887 value_type const* operator->() const
14888 {
14889 return &** this;
14890 }
14891
14892 private:
14893 mutable value_type owned_value = nullptr;
14894 value_type const* value_ref = nullptr;
14895};
14896
14897} // namespace detail
14898NLOHMANN_JSON_NAMESPACE_END
14899
14900// #include <nlohmann/detail/macro_scope.hpp>
14901
14902// #include <nlohmann/detail/string_concat.hpp>
14903
14904// #include <nlohmann/detail/string_escape.hpp>
14905
14906// #include <nlohmann/detail/meta/cpp_future.hpp>
14907
14908// #include <nlohmann/detail/meta/type_traits.hpp>
14909
14910// #include <nlohmann/detail/output/binary_writer.hpp>
14911// __ _____ _____ _____
14912// __| | __| | | | JSON for Modern C++
14913// | | |__ | | | | | | version 3.11.3
14914// |_____|_____|_____|_|___| https://github.com/nlohmann/json
14915//
14916// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
14917// SPDX-License-Identifier: MIT
14918
14919
14920
14921#include <algorithm> // reverse
14922#include <array> // array
14923#include <map> // map
14924#include <cmath> // isnan, isinf
14925#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
14926#include <cstring> // memcpy
14927#include <limits> // numeric_limits
14928#include <string> // string
14929#include <utility> // move
14930#include <vector> // vector
14931
14932// #include <nlohmann/detail/input/binary_reader.hpp>
14933
14934// #include <nlohmann/detail/macro_scope.hpp>
14935
14936// #include <nlohmann/detail/output/output_adapters.hpp>
14937// __ _____ _____ _____
14938// __| | __| | | | JSON for Modern C++
14939// | | |__ | | | | | | version 3.11.3
14940// |_____|_____|_____|_|___| https://github.com/nlohmann/json
14941//
14942// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
14943// SPDX-License-Identifier: MIT
14944
14945
14946
14947#include <algorithm> // copy
14948#include <cstddef> // size_t
14949#include <iterator> // back_inserter
14950#include <memory> // shared_ptr, make_shared
14951#include <string> // basic_string
14952#include <vector> // vector
14953
14954#ifndef JSON_NO_IO
14955 #include <ios> // streamsize
14956 #include <ostream> // basic_ostream
14957#endif // JSON_NO_IO
14958
14959// #include <nlohmann/detail/macro_scope.hpp>
14960
14961
14962NLOHMANN_JSON_NAMESPACE_BEGIN
14963namespace detail
14964{
14965
14967template<typename CharType> struct output_adapter_protocol
14968{
14969 virtual void write_character(CharType c) = 0;
14970 virtual void write_characters(const CharType* s, std::size_t length) = 0;
14971 virtual ~output_adapter_protocol() = default;
14972
14973 output_adapter_protocol() = default;
14976 output_adapter_protocol& operator=(const output_adapter_protocol&) = default;
14977 output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default;
14978};
14979
14981template<typename CharType>
14982using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;
14983
14985template<typename CharType, typename AllocatorType = std::allocator<CharType>>
14987{
14988 public:
14989 explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept
14990 : v(vec)
14991 {}
14992
14993 void write_character(CharType c) override
14994 {
14995 v.push_back(c);
14996 }
14997
14998 JSON_HEDLEY_NON_NULL(2)
14999 void write_characters(const CharType* s, std::size_t length) override
15000 {
15001 v.insert(v.end(), s, s + length);
15002 }
15003
15004 private:
15005 std::vector<CharType, AllocatorType>& v;
15006};
15007
15008#ifndef JSON_NO_IO
15010template<typename CharType>
15012{
15013 public:
15014 explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept
15015 : stream(s)
15016 {}
15017
15018 void write_character(CharType c) override
15019 {
15020 stream.put(c);
15021 }
15022
15023 JSON_HEDLEY_NON_NULL(2)
15024 void write_characters(const CharType* s, std::size_t length) override
15025 {
15026 stream.write(s, static_cast<std::streamsize>(length));
15027 }
15028
15029 private:
15030 std::basic_ostream<CharType>& stream;
15031};
15032#endif // JSON_NO_IO
15033
15035template<typename CharType, typename StringType = std::basic_string<CharType>>
15037{
15038 public:
15039 explicit output_string_adapter(StringType& s) noexcept
15040 : str(s)
15041 {}
15042
15043 void write_character(CharType c) override
15044 {
15045 str.push_back(c);
15046 }
15047
15048 JSON_HEDLEY_NON_NULL(2)
15049 void write_characters(const CharType* s, std::size_t length) override
15050 {
15051 str.append(s, length);
15052 }
15053
15054 private:
15055 StringType& str;
15056};
15057
15058template<typename CharType, typename StringType = std::basic_string<CharType>>
15060{
15061 public:
15062 template<typename AllocatorType = std::allocator<CharType>>
15063 output_adapter(std::vector<CharType, AllocatorType>& vec)
15064 : oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {}
15065
15066#ifndef JSON_NO_IO
15067 output_adapter(std::basic_ostream<CharType>& s)
15068 : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
15069#endif // JSON_NO_IO
15070
15071 output_adapter(StringType& s)
15072 : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
15073
15075 {
15076 return oa;
15077 }
15078
15079 private:
15080 output_adapter_t<CharType> oa = nullptr;
15081};
15082
15083} // namespace detail
15084NLOHMANN_JSON_NAMESPACE_END
15085
15086// #include <nlohmann/detail/string_concat.hpp>
15087
15088
15089NLOHMANN_JSON_NAMESPACE_BEGIN
15090namespace detail
15091{
15092
15094// binary writer //
15096
15100template<typename BasicJsonType, typename CharType>
15102{
15103 using string_t = typename BasicJsonType::string_t;
15104 using binary_t = typename BasicJsonType::binary_t;
15105 using number_float_t = typename BasicJsonType::number_float_t;
15106
15107 public:
15113 explicit binary_writer(output_adapter_t<CharType> adapter) : oa(std::move(adapter))
15114 {
15115 JSON_ASSERT(oa);
15116 }
15117
15122 void write_bson(const BasicJsonType& j)
15123 {
15124 switch (j.type())
15125 {
15126 case value_t::object:
15127 {
15128 write_bson_object(*j.m_data.m_value.object);
15129 break;
15130 }
15131
15132 case value_t::null:
15133 case value_t::array:
15134 case value_t::string:
15135 case value_t::boolean:
15136 case value_t::number_integer:
15137 case value_t::number_unsigned:
15138 case value_t::number_float:
15139 case value_t::binary:
15140 case value_t::discarded:
15141 default:
15142 {
15143 JSON_THROW(type_error::create(317, concat("to serialize to BSON, top-level type must be object, but is ", j.type_name()), &j));
15144 }
15145 }
15146 }
15147
15151 void write_cbor(const BasicJsonType& j)
15152 {
15153 switch (j.type())
15154 {
15155 case value_t::null:
15156 {
15157 oa->write_character(to_char_type(0xF6));
15158 break;
15159 }
15160
15161 case value_t::boolean:
15162 {
15163 oa->write_character(j.m_data.m_value.boolean
15164 ? to_char_type(0xF5)
15165 : to_char_type(0xF4));
15166 break;
15167 }
15168
15169 case value_t::number_integer:
15170 {
15171 if (j.m_data.m_value.number_integer >= 0)
15172 {
15173 // CBOR does not differentiate between positive signed
15174 // integers and unsigned integers. Therefore, we used the
15175 // code from the value_t::number_unsigned case here.
15176 if (j.m_data.m_value.number_integer <= 0x17)
15177 {
15178 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
15179 }
15180 else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
15181 {
15182 oa->write_character(to_char_type(0x18));
15183 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
15184 }
15185 else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
15186 {
15187 oa->write_character(to_char_type(0x19));
15188 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
15189 }
15190 else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
15191 {
15192 oa->write_character(to_char_type(0x1A));
15193 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
15194 }
15195 else
15196 {
15197 oa->write_character(to_char_type(0x1B));
15198 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
15199 }
15200 }
15201 else
15202 {
15203 // The conversions below encode the sign in the first
15204 // byte, and the value is converted to a positive number.
15205 const auto positive_number = -1 - j.m_data.m_value.number_integer;
15206 if (j.m_data.m_value.number_integer >= -24)
15207 {
15208 write_number(static_cast<std::uint8_t>(0x20 + positive_number));
15209 }
15210 else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
15211 {
15212 oa->write_character(to_char_type(0x38));
15213 write_number(static_cast<std::uint8_t>(positive_number));
15214 }
15215 else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
15216 {
15217 oa->write_character(to_char_type(0x39));
15218 write_number(static_cast<std::uint16_t>(positive_number));
15219 }
15220 else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
15221 {
15222 oa->write_character(to_char_type(0x3A));
15223 write_number(static_cast<std::uint32_t>(positive_number));
15224 }
15225 else
15226 {
15227 oa->write_character(to_char_type(0x3B));
15228 write_number(static_cast<std::uint64_t>(positive_number));
15229 }
15230 }
15231 break;
15232 }
15233
15234 case value_t::number_unsigned:
15235 {
15236 if (j.m_data.m_value.number_unsigned <= 0x17)
15237 {
15238 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
15239 }
15240 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
15241 {
15242 oa->write_character(to_char_type(0x18));
15243 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));
15244 }
15245 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
15246 {
15247 oa->write_character(to_char_type(0x19));
15248 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_unsigned));
15249 }
15250 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
15251 {
15252 oa->write_character(to_char_type(0x1A));
15253 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_unsigned));
15254 }
15255 else
15256 {
15257 oa->write_character(to_char_type(0x1B));
15258 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned));
15259 }
15260 break;
15261 }
15262
15263 case value_t::number_float:
15264 {
15265 if (std::isnan(j.m_data.m_value.number_float))
15266 {
15267 // NaN is 0xf97e00 in CBOR
15268 oa->write_character(to_char_type(0xF9));
15269 oa->write_character(to_char_type(0x7E));
15270 oa->write_character(to_char_type(0x00));
15271 }
15272 else if (std::isinf(j.m_data.m_value.number_float))
15273 {
15274 // Infinity is 0xf97c00, -Infinity is 0xf9fc00
15275 oa->write_character(to_char_type(0xf9));
15276 oa->write_character(j.m_data.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));
15277 oa->write_character(to_char_type(0x00));
15278 }
15279 else
15280 {
15281 write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::cbor);
15282 }
15283 break;
15284 }
15285
15286 case value_t::string:
15287 {
15288 // step 1: write control byte and the string length
15289 const auto N = j.m_data.m_value.string->size();
15290 if (N <= 0x17)
15291 {
15292 write_number(static_cast<std::uint8_t>(0x60 + N));
15293 }
15294 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
15295 {
15296 oa->write_character(to_char_type(0x78));
15297 write_number(static_cast<std::uint8_t>(N));
15298 }
15299 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
15300 {
15301 oa->write_character(to_char_type(0x79));
15302 write_number(static_cast<std::uint16_t>(N));
15303 }
15304 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
15305 {
15306 oa->write_character(to_char_type(0x7A));
15307 write_number(static_cast<std::uint32_t>(N));
15308 }
15309 // LCOV_EXCL_START
15310 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
15311 {
15312 oa->write_character(to_char_type(0x7B));
15313 write_number(static_cast<std::uint64_t>(N));
15314 }
15315 // LCOV_EXCL_STOP
15316
15317 // step 2: write the string
15318 oa->write_characters(
15319 reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
15320 j.m_data.m_value.string->size());
15321 break;
15322 }
15323
15324 case value_t::array:
15325 {
15326 // step 1: write control byte and the array size
15327 const auto N = j.m_data.m_value.array->size();
15328 if (N <= 0x17)
15329 {
15330 write_number(static_cast<std::uint8_t>(0x80 + N));
15331 }
15332 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
15333 {
15334 oa->write_character(to_char_type(0x98));
15335 write_number(static_cast<std::uint8_t>(N));
15336 }
15337 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
15338 {
15339 oa->write_character(to_char_type(0x99));
15340 write_number(static_cast<std::uint16_t>(N));
15341 }
15342 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
15343 {
15344 oa->write_character(to_char_type(0x9A));
15345 write_number(static_cast<std::uint32_t>(N));
15346 }
15347 // LCOV_EXCL_START
15348 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
15349 {
15350 oa->write_character(to_char_type(0x9B));
15351 write_number(static_cast<std::uint64_t>(N));
15352 }
15353 // LCOV_EXCL_STOP
15354
15355 // step 2: write each element
15356 for (const auto& el : *j.m_data.m_value.array)
15357 {
15358 write_cbor(el);
15359 }
15360 break;
15361 }
15362
15363 case value_t::binary:
15364 {
15365 if (j.m_data.m_value.binary->has_subtype())
15366 {
15367 if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)())
15368 {
15369 write_number(static_cast<std::uint8_t>(0xd8));
15370 write_number(static_cast<std::uint8_t>(j.m_data.m_value.binary->subtype()));
15371 }
15372 else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)())
15373 {
15374 write_number(static_cast<std::uint8_t>(0xd9));
15375 write_number(static_cast<std::uint16_t>(j.m_data.m_value.binary->subtype()));
15376 }
15377 else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)())
15378 {
15379 write_number(static_cast<std::uint8_t>(0xda));
15380 write_number(static_cast<std::uint32_t>(j.m_data.m_value.binary->subtype()));
15381 }
15382 else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())
15383 {
15384 write_number(static_cast<std::uint8_t>(0xdb));
15385 write_number(static_cast<std::uint64_t>(j.m_data.m_value.binary->subtype()));
15386 }
15387 }
15388
15389 // step 1: write control byte and the binary array size
15390 const auto N = j.m_data.m_value.binary->size();
15391 if (N <= 0x17)
15392 {
15393 write_number(static_cast<std::uint8_t>(0x40 + N));
15394 }
15395 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
15396 {
15397 oa->write_character(to_char_type(0x58));
15398 write_number(static_cast<std::uint8_t>(N));
15399 }
15400 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
15401 {
15402 oa->write_character(to_char_type(0x59));
15403 write_number(static_cast<std::uint16_t>(N));
15404 }
15405 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
15406 {
15407 oa->write_character(to_char_type(0x5A));
15408 write_number(static_cast<std::uint32_t>(N));
15409 }
15410 // LCOV_EXCL_START
15411 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
15412 {
15413 oa->write_character(to_char_type(0x5B));
15414 write_number(static_cast<std::uint64_t>(N));
15415 }
15416 // LCOV_EXCL_STOP
15417
15418 // step 2: write each element
15419 oa->write_characters(
15420 reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
15421 N);
15422
15423 break;
15424 }
15425
15426 case value_t::object:
15427 {
15428 // step 1: write control byte and the object size
15429 const auto N = j.m_data.m_value.object->size();
15430 if (N <= 0x17)
15431 {
15432 write_number(static_cast<std::uint8_t>(0xA0 + N));
15433 }
15434 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
15435 {
15436 oa->write_character(to_char_type(0xB8));
15437 write_number(static_cast<std::uint8_t>(N));
15438 }
15439 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
15440 {
15441 oa->write_character(to_char_type(0xB9));
15442 write_number(static_cast<std::uint16_t>(N));
15443 }
15444 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
15445 {
15446 oa->write_character(to_char_type(0xBA));
15447 write_number(static_cast<std::uint32_t>(N));
15448 }
15449 // LCOV_EXCL_START
15450 else if (N <= (std::numeric_limits<std::uint64_t>::max)())
15451 {
15452 oa->write_character(to_char_type(0xBB));
15453 write_number(static_cast<std::uint64_t>(N));
15454 }
15455 // LCOV_EXCL_STOP
15456
15457 // step 2: write each element
15458 for (const auto& el : *j.m_data.m_value.object)
15459 {
15460 write_cbor(el.first);
15461 write_cbor(el.second);
15462 }
15463 break;
15464 }
15465
15466 case value_t::discarded:
15467 default:
15468 break;
15469 }
15470 }
15471
15475 void write_msgpack(const BasicJsonType& j)
15476 {
15477 switch (j.type())
15478 {
15479 case value_t::null: // nil
15480 {
15481 oa->write_character(to_char_type(0xC0));
15482 break;
15483 }
15484
15485 case value_t::boolean: // true and false
15486 {
15487 oa->write_character(j.m_data.m_value.boolean
15488 ? to_char_type(0xC3)
15489 : to_char_type(0xC2));
15490 break;
15491 }
15492
15493 case value_t::number_integer:
15494 {
15495 if (j.m_data.m_value.number_integer >= 0)
15496 {
15497 // MessagePack does not differentiate between positive
15498 // signed integers and unsigned integers. Therefore, we used
15499 // the code from the value_t::number_unsigned case here.
15500 if (j.m_data.m_value.number_unsigned < 128)
15501 {
15502 // positive fixnum
15503 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
15504 }
15505 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
15506 {
15507 // uint 8
15508 oa->write_character(to_char_type(0xCC));
15509 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
15510 }
15511 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
15512 {
15513 // uint 16
15514 oa->write_character(to_char_type(0xCD));
15515 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
15516 }
15517 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
15518 {
15519 // uint 32
15520 oa->write_character(to_char_type(0xCE));
15521 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
15522 }
15523 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
15524 {
15525 // uint 64
15526 oa->write_character(to_char_type(0xCF));
15527 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
15528 }
15529 }
15530 else
15531 {
15532 if (j.m_data.m_value.number_integer >= -32)
15533 {
15534 // negative fixnum
15535 write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
15536 }
15537 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&
15538 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
15539 {
15540 // int 8
15541 oa->write_character(to_char_type(0xD0));
15542 write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));
15543 }
15544 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&
15545 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
15546 {
15547 // int 16
15548 oa->write_character(to_char_type(0xD1));
15549 write_number(static_cast<std::int16_t>(j.m_data.m_value.number_integer));
15550 }
15551 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&
15552 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
15553 {
15554 // int 32
15555 oa->write_character(to_char_type(0xD2));
15556 write_number(static_cast<std::int32_t>(j.m_data.m_value.number_integer));
15557 }
15558 else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&
15559 j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
15560 {
15561 // int 64
15562 oa->write_character(to_char_type(0xD3));
15563 write_number(static_cast<std::int64_t>(j.m_data.m_value.number_integer));
15564 }
15565 }
15566 break;
15567 }
15568
15569 case value_t::number_unsigned:
15570 {
15571 if (j.m_data.m_value.number_unsigned < 128)
15572 {
15573 // positive fixnum
15574 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
15575 }
15576 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
15577 {
15578 // uint 8
15579 oa->write_character(to_char_type(0xCC));
15580 write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));
15581 }
15582 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
15583 {
15584 // uint 16
15585 oa->write_character(to_char_type(0xCD));
15586 write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));
15587 }
15588 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
15589 {
15590 // uint 32
15591 oa->write_character(to_char_type(0xCE));
15592 write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));
15593 }
15594 else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
15595 {
15596 // uint 64
15597 oa->write_character(to_char_type(0xCF));
15598 write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));
15599 }
15600 break;
15601 }
15602
15603 case value_t::number_float:
15604 {
15605 write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::msgpack);
15606 break;
15607 }
15608
15609 case value_t::string:
15610 {
15611 // step 1: write control byte and the string length
15612 const auto N = j.m_data.m_value.string->size();
15613 if (N <= 31)
15614 {
15615 // fixstr
15616 write_number(static_cast<std::uint8_t>(0xA0 | N));
15617 }
15618 else if (N <= (std::numeric_limits<std::uint8_t>::max)())
15619 {
15620 // str 8
15621 oa->write_character(to_char_type(0xD9));
15622 write_number(static_cast<std::uint8_t>(N));
15623 }
15624 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
15625 {
15626 // str 16
15627 oa->write_character(to_char_type(0xDA));
15628 write_number(static_cast<std::uint16_t>(N));
15629 }
15630 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
15631 {
15632 // str 32
15633 oa->write_character(to_char_type(0xDB));
15634 write_number(static_cast<std::uint32_t>(N));
15635 }
15636
15637 // step 2: write the string
15638 oa->write_characters(
15639 reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
15640 j.m_data.m_value.string->size());
15641 break;
15642 }
15643
15644 case value_t::array:
15645 {
15646 // step 1: write control byte and the array size
15647 const auto N = j.m_data.m_value.array->size();
15648 if (N <= 15)
15649 {
15650 // fixarray
15651 write_number(static_cast<std::uint8_t>(0x90 | N));
15652 }
15653 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
15654 {
15655 // array 16
15656 oa->write_character(to_char_type(0xDC));
15657 write_number(static_cast<std::uint16_t>(N));
15658 }
15659 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
15660 {
15661 // array 32
15662 oa->write_character(to_char_type(0xDD));
15663 write_number(static_cast<std::uint32_t>(N));
15664 }
15665
15666 // step 2: write each element
15667 for (const auto& el : *j.m_data.m_value.array)
15668 {
15669 write_msgpack(el);
15670 }
15671 break;
15672 }
15673
15674 case value_t::binary:
15675 {
15676 // step 0: determine if the binary type has a set subtype to
15677 // determine whether or not to use the ext or fixext types
15678 const bool use_ext = j.m_data.m_value.binary->has_subtype();
15679
15680 // step 1: write control byte and the byte string length
15681 const auto N = j.m_data.m_value.binary->size();
15682 if (N <= (std::numeric_limits<std::uint8_t>::max)())
15683 {
15684 std::uint8_t output_type{};
15685 bool fixed = true;
15686 if (use_ext)
15687 {
15688 switch (N)
15689 {
15690 case 1:
15691 output_type = 0xD4; // fixext 1
15692 break;
15693 case 2:
15694 output_type = 0xD5; // fixext 2
15695 break;
15696 case 4:
15697 output_type = 0xD6; // fixext 4
15698 break;
15699 case 8:
15700 output_type = 0xD7; // fixext 8
15701 break;
15702 case 16:
15703 output_type = 0xD8; // fixext 16
15704 break;
15705 default:
15706 output_type = 0xC7; // ext 8
15707 fixed = false;
15708 break;
15709 }
15710
15711 }
15712 else
15713 {
15714 output_type = 0xC4; // bin 8
15715 fixed = false;
15716 }
15717
15718 oa->write_character(to_char_type(output_type));
15719 if (!fixed)
15720 {
15721 write_number(static_cast<std::uint8_t>(N));
15722 }
15723 }
15724 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
15725 {
15726 const std::uint8_t output_type = use_ext
15727 ? 0xC8 // ext 16
15728 : 0xC5; // bin 16
15729
15730 oa->write_character(to_char_type(output_type));
15731 write_number(static_cast<std::uint16_t>(N));
15732 }
15733 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
15734 {
15735 const std::uint8_t output_type = use_ext
15736 ? 0xC9 // ext 32
15737 : 0xC6; // bin 32
15738
15739 oa->write_character(to_char_type(output_type));
15740 write_number(static_cast<std::uint32_t>(N));
15741 }
15742
15743 // step 1.5: if this is an ext type, write the subtype
15744 if (use_ext)
15745 {
15746 write_number(static_cast<std::int8_t>(j.m_data.m_value.binary->subtype()));
15747 }
15748
15749 // step 2: write the byte string
15750 oa->write_characters(
15751 reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
15752 N);
15753
15754 break;
15755 }
15756
15757 case value_t::object:
15758 {
15759 // step 1: write control byte and the object size
15760 const auto N = j.m_data.m_value.object->size();
15761 if (N <= 15)
15762 {
15763 // fixmap
15764 write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));
15765 }
15766 else if (N <= (std::numeric_limits<std::uint16_t>::max)())
15767 {
15768 // map 16
15769 oa->write_character(to_char_type(0xDE));
15770 write_number(static_cast<std::uint16_t>(N));
15771 }
15772 else if (N <= (std::numeric_limits<std::uint32_t>::max)())
15773 {
15774 // map 32
15775 oa->write_character(to_char_type(0xDF));
15776 write_number(static_cast<std::uint32_t>(N));
15777 }
15778
15779 // step 2: write each element
15780 for (const auto& el : *j.m_data.m_value.object)
15781 {
15782 write_msgpack(el.first);
15783 write_msgpack(el.second);
15784 }
15785 break;
15786 }
15787
15788 case value_t::discarded:
15789 default:
15790 break;
15791 }
15792 }
15793
15801 void write_ubjson(const BasicJsonType& j, const bool use_count,
15802 const bool use_type, const bool add_prefix = true,
15803 const bool use_bjdata = false)
15804 {
15805 switch (j.type())
15806 {
15807 case value_t::null:
15808 {
15809 if (add_prefix)
15810 {
15811 oa->write_character(to_char_type('Z'));
15812 }
15813 break;
15814 }
15815
15816 case value_t::boolean:
15817 {
15818 if (add_prefix)
15819 {
15820 oa->write_character(j.m_data.m_value.boolean
15821 ? to_char_type('T')
15822 : to_char_type('F'));
15823 }
15824 break;
15825 }
15826
15827 case value_t::number_integer:
15828 {
15829 write_number_with_ubjson_prefix(j.m_data.m_value.number_integer, add_prefix, use_bjdata);
15830 break;
15831 }
15832
15833 case value_t::number_unsigned:
15834 {
15835 write_number_with_ubjson_prefix(j.m_data.m_value.number_unsigned, add_prefix, use_bjdata);
15836 break;
15837 }
15838
15839 case value_t::number_float:
15840 {
15841 write_number_with_ubjson_prefix(j.m_data.m_value.number_float, add_prefix, use_bjdata);
15842 break;
15843 }
15844
15845 case value_t::string:
15846 {
15847 if (add_prefix)
15848 {
15849 oa->write_character(to_char_type('S'));
15850 }
15851 write_number_with_ubjson_prefix(j.m_data.m_value.string->size(), true, use_bjdata);
15852 oa->write_characters(
15853 reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),
15854 j.m_data.m_value.string->size());
15855 break;
15856 }
15857
15858 case value_t::array:
15859 {
15860 if (add_prefix)
15861 {
15862 oa->write_character(to_char_type('['));
15863 }
15864
15865 bool prefix_required = true;
15866 if (use_type && !j.m_data.m_value.array->empty())
15867 {
15868 JSON_ASSERT(use_count);
15869 const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
15870 const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
15871 [this, first_prefix, use_bjdata](const BasicJsonType & v)
15872 {
15873 return ubjson_prefix(v, use_bjdata) == first_prefix;
15874 });
15875
15876 std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
15877
15878 if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
15879 {
15880 prefix_required = false;
15881 oa->write_character(to_char_type('$'));
15882 oa->write_character(first_prefix);
15883 }
15884 }
15885
15886 if (use_count)
15887 {
15888 oa->write_character(to_char_type('#'));
15889 write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata);
15890 }
15891
15892 for (const auto& el : *j.m_data.m_value.array)
15893 {
15894 write_ubjson(el, use_count, use_type, prefix_required, use_bjdata);
15895 }
15896
15897 if (!use_count)
15898 {
15899 oa->write_character(to_char_type(']'));
15900 }
15901
15902 break;
15903 }
15904
15905 case value_t::binary:
15906 {
15907 if (add_prefix)
15908 {
15909 oa->write_character(to_char_type('['));
15910 }
15911
15912 if (use_type && !j.m_data.m_value.binary->empty())
15913 {
15914 JSON_ASSERT(use_count);
15915 oa->write_character(to_char_type('$'));
15916 oa->write_character('U');
15917 }
15918
15919 if (use_count)
15920 {
15921 oa->write_character(to_char_type('#'));
15922 write_number_with_ubjson_prefix(j.m_data.m_value.binary->size(), true, use_bjdata);
15923 }
15924
15925 if (use_type)
15926 {
15927 oa->write_characters(
15928 reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),
15929 j.m_data.m_value.binary->size());
15930 }
15931 else
15932 {
15933 for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i)
15934 {
15935 oa->write_character(to_char_type('U'));
15936 oa->write_character(j.m_data.m_value.binary->data()[i]);
15937 }
15938 }
15939
15940 if (!use_count)
15941 {
15942 oa->write_character(to_char_type(']'));
15943 }
15944
15945 break;
15946 }
15947
15948 case value_t::object:
15949 {
15950 if (use_bjdata && j.m_data.m_value.object->size() == 3 && j.m_data.m_value.object->find("_ArrayType_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArraySize_") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find("_ArrayData_") != j.m_data.m_value.object->end())
15951 {
15952 if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type)) // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata)
15953 {
15954 break;
15955 }
15956 }
15957
15958 if (add_prefix)
15959 {
15960 oa->write_character(to_char_type('{'));
15961 }
15962
15963 bool prefix_required = true;
15964 if (use_type && !j.m_data.m_value.object->empty())
15965 {
15966 JSON_ASSERT(use_count);
15967 const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
15968 const bool same_prefix = std::all_of(j.begin(), j.end(),
15969 [this, first_prefix, use_bjdata](const BasicJsonType & v)
15970 {
15971 return ubjson_prefix(v, use_bjdata) == first_prefix;
15972 });
15973
15974 std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
15975
15976 if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
15977 {
15978 prefix_required = false;
15979 oa->write_character(to_char_type('$'));
15980 oa->write_character(first_prefix);
15981 }
15982 }
15983
15984 if (use_count)
15985 {
15986 oa->write_character(to_char_type('#'));
15987 write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata);
15988 }
15989
15990 for (const auto& el : *j.m_data.m_value.object)
15991 {
15992 write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata);
15993 oa->write_characters(
15994 reinterpret_cast<const CharType*>(el.first.c_str()),
15995 el.first.size());
15996 write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata);
15997 }
15998
15999 if (!use_count)
16000 {
16001 oa->write_character(to_char_type('}'));
16002 }
16003
16004 break;
16005 }
16006
16007 case value_t::discarded:
16008 default:
16009 break;
16010 }
16011 }
16012
16013 private:
16015 // BSON //
16017
16022 static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j)
16023 {
16024 const auto it = name.find(static_cast<typename string_t::value_type>(0));
16025 if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))
16026 {
16027 JSON_THROW(out_of_range::create(409, concat("BSON key cannot contain code point U+0000 (at byte ", std::to_string(it), ")"), &j));
16028 static_cast<void>(j);
16029 }
16030
16031 return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;
16032 }
16033
16037 void write_bson_entry_header(const string_t& name,
16038 const std::uint8_t element_type)
16039 {
16040 oa->write_character(to_char_type(element_type)); // boolean
16041 oa->write_characters(
16042 reinterpret_cast<const CharType*>(name.c_str()),
16043 name.size() + 1u);
16044 }
16045
16049 void write_bson_boolean(const string_t& name,
16050 const bool value)
16051 {
16052 write_bson_entry_header(name, 0x08);
16053 oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));
16054 }
16055
16059 void write_bson_double(const string_t& name,
16060 const double value)
16061 {
16062 write_bson_entry_header(name, 0x01);
16063 write_number<double>(value, true);
16064 }
16065
16069 static std::size_t calc_bson_string_size(const string_t& value)
16070 {
16071 return sizeof(std::int32_t) + value.size() + 1ul;
16072 }
16073
16077 void write_bson_string(const string_t& name,
16078 const string_t& value)
16079 {
16080 write_bson_entry_header(name, 0x02);
16081
16082 write_number<std::int32_t>(static_cast<std::int32_t>(value.size() + 1ul), true);
16083 oa->write_characters(
16084 reinterpret_cast<const CharType*>(value.c_str()),
16085 value.size() + 1);
16086 }
16087
16091 void write_bson_null(const string_t& name)
16092 {
16093 write_bson_entry_header(name, 0x0A);
16094 }
16095
16099 static std::size_t calc_bson_integer_size(const std::int64_t value)
16100 {
16101 return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()
16102 ? sizeof(std::int32_t)
16103 : sizeof(std::int64_t);
16104 }
16105
16109 void write_bson_integer(const string_t& name,
16110 const std::int64_t value)
16111 {
16112 if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())
16113 {
16114 write_bson_entry_header(name, 0x10); // int32
16115 write_number<std::int32_t>(static_cast<std::int32_t>(value), true);
16116 }
16117 else
16118 {
16119 write_bson_entry_header(name, 0x12); // int64
16120 write_number<std::int64_t>(static_cast<std::int64_t>(value), true);
16121 }
16122 }
16123
16127 static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
16128 {
16129 return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
16130 ? sizeof(std::int32_t)
16131 : sizeof(std::int64_t);
16132 }
16133
16137 void write_bson_unsigned(const string_t& name,
16138 const BasicJsonType& j)
16139 {
16140 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
16141 {
16142 write_bson_entry_header(name, 0x10 /* int32 */);
16143 write_number<std::int32_t>(static_cast<std::int32_t>(j.m_data.m_value.number_unsigned), true);
16144 }
16145 else if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
16146 {
16147 write_bson_entry_header(name, 0x12 /* int64 */);
16148 write_number<std::int64_t>(static_cast<std::int64_t>(j.m_data.m_value.number_unsigned), true);
16149 }
16150 else
16151 {
16152 JSON_THROW(out_of_range::create(407, concat("integer number ", std::to_string(j.m_data.m_value.number_unsigned), " cannot be represented by BSON as it does not fit int64"), &j));
16153 }
16154 }
16155
16159 void write_bson_object_entry(const string_t& name,
16160 const typename BasicJsonType::object_t& value)
16161 {
16162 write_bson_entry_header(name, 0x03); // object
16163 write_bson_object(value);
16164 }
16165
16169 static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)
16170 {
16171 std::size_t array_index = 0ul;
16172
16173 const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast<std::size_t>(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)
16174 {
16175 return result + calc_bson_element_size(std::to_string(array_index++), el);
16176 });
16177
16178 return sizeof(std::int32_t) + embedded_document_size + 1ul;
16179 }
16180
16184 static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value)
16185 {
16186 return sizeof(std::int32_t) + value.size() + 1ul;
16187 }
16188
16192 void write_bson_array(const string_t& name,
16193 const typename BasicJsonType::array_t& value)
16194 {
16195 write_bson_entry_header(name, 0x04); // array
16196 write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_array_size(value)), true);
16197
16198 std::size_t array_index = 0ul;
16199
16200 for (const auto& el : value)
16201 {
16202 write_bson_element(std::to_string(array_index++), el);
16203 }
16204
16205 oa->write_character(to_char_type(0x00));
16206 }
16207
16211 void write_bson_binary(const string_t& name,
16212 const binary_t& value)
16213 {
16214 write_bson_entry_header(name, 0x05);
16215
16216 write_number<std::int32_t>(static_cast<std::int32_t>(value.size()), true);
16217 write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00));
16218
16219 oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());
16220 }
16221
16226 static std::size_t calc_bson_element_size(const string_t& name,
16227 const BasicJsonType& j)
16228 {
16229 const auto header_size = calc_bson_entry_header_size(name, j);
16230 switch (j.type())
16231 {
16232 case value_t::object:
16233 return header_size + calc_bson_object_size(*j.m_data.m_value.object);
16234
16235 case value_t::array:
16236 return header_size + calc_bson_array_size(*j.m_data.m_value.array);
16237
16238 case value_t::binary:
16239 return header_size + calc_bson_binary_size(*j.m_data.m_value.binary);
16240
16241 case value_t::boolean:
16242 return header_size + 1ul;
16243
16244 case value_t::number_float:
16245 return header_size + 8ul;
16246
16247 case value_t::number_integer:
16248 return header_size + calc_bson_integer_size(j.m_data.m_value.number_integer);
16249
16250 case value_t::number_unsigned:
16251 return header_size + calc_bson_unsigned_size(j.m_data.m_value.number_unsigned);
16252
16253 case value_t::string:
16254 return header_size + calc_bson_string_size(*j.m_data.m_value.string);
16255
16256 case value_t::null:
16257 return header_size + 0ul;
16258
16259 // LCOV_EXCL_START
16260 case value_t::discarded:
16261 default:
16262 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
16263 return 0ul;
16264 // LCOV_EXCL_STOP
16265 }
16266 }
16267
16274 void write_bson_element(const string_t& name,
16275 const BasicJsonType& j)
16276 {
16277 switch (j.type())
16278 {
16279 case value_t::object:
16280 return write_bson_object_entry(name, *j.m_data.m_value.object);
16281
16282 case value_t::array:
16283 return write_bson_array(name, *j.m_data.m_value.array);
16284
16285 case value_t::binary:
16286 return write_bson_binary(name, *j.m_data.m_value.binary);
16287
16288 case value_t::boolean:
16289 return write_bson_boolean(name, j.m_data.m_value.boolean);
16290
16291 case value_t::number_float:
16292 return write_bson_double(name, j.m_data.m_value.number_float);
16293
16294 case value_t::number_integer:
16295 return write_bson_integer(name, j.m_data.m_value.number_integer);
16296
16297 case value_t::number_unsigned:
16298 return write_bson_unsigned(name, j);
16299
16300 case value_t::string:
16301 return write_bson_string(name, *j.m_data.m_value.string);
16302
16303 case value_t::null:
16304 return write_bson_null(name);
16305
16306 // LCOV_EXCL_START
16307 case value_t::discarded:
16308 default:
16309 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
16310 return;
16311 // LCOV_EXCL_STOP
16312 }
16313 }
16314
16321 static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
16322 {
16323 const std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0),
16324 [](size_t result, const typename BasicJsonType::object_t::value_type & el)
16325 {
16326 return result += calc_bson_element_size(el.first, el.second);
16327 });
16328
16329 return sizeof(std::int32_t) + document_size + 1ul;
16330 }
16331
16336 void write_bson_object(const typename BasicJsonType::object_t& value)
16337 {
16338 write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_object_size(value)), true);
16339
16340 for (const auto& el : value)
16341 {
16342 write_bson_element(el.first, el.second);
16343 }
16344
16345 oa->write_character(to_char_type(0x00));
16346 }
16347
16349 // CBOR //
16351
16352 static constexpr CharType get_cbor_float_prefix(float /*unused*/)
16353 {
16354 return to_char_type(0xFA); // Single-Precision Float
16355 }
16356
16357 static constexpr CharType get_cbor_float_prefix(double /*unused*/)
16358 {
16359 return to_char_type(0xFB); // Double-Precision Float
16360 }
16361
16363 // MsgPack //
16365
16366 static constexpr CharType get_msgpack_float_prefix(float /*unused*/)
16367 {
16368 return to_char_type(0xCA); // float 32
16369 }
16370
16371 static constexpr CharType get_msgpack_float_prefix(double /*unused*/)
16372 {
16373 return to_char_type(0xCB); // float 64
16374 }
16375
16377 // UBJSON //
16379
16380 // UBJSON: write number (floating point)
16381 template<typename NumberType, typename std::enable_if<
16382 std::is_floating_point<NumberType>::value, int>::type = 0>
16383 void write_number_with_ubjson_prefix(const NumberType n,
16384 const bool add_prefix,
16385 const bool use_bjdata)
16386 {
16387 if (add_prefix)
16388 {
16389 oa->write_character(get_ubjson_float_prefix(n));
16390 }
16391 write_number(n, use_bjdata);
16392 }
16393
16394 // UBJSON: write number (unsigned integer)
16395 template<typename NumberType, typename std::enable_if<
16396 std::is_unsigned<NumberType>::value, int>::type = 0>
16397 void write_number_with_ubjson_prefix(const NumberType n,
16398 const bool add_prefix,
16399 const bool use_bjdata)
16400 {
16401 if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
16402 {
16403 if (add_prefix)
16404 {
16405 oa->write_character(to_char_type('i')); // int8
16406 }
16407 write_number(static_cast<std::uint8_t>(n), use_bjdata);
16408 }
16409 else if (n <= (std::numeric_limits<std::uint8_t>::max)())
16410 {
16411 if (add_prefix)
16412 {
16413 oa->write_character(to_char_type('U')); // uint8
16414 }
16415 write_number(static_cast<std::uint8_t>(n), use_bjdata);
16416 }
16417 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
16418 {
16419 if (add_prefix)
16420 {
16421 oa->write_character(to_char_type('I')); // int16
16422 }
16423 write_number(static_cast<std::int16_t>(n), use_bjdata);
16424 }
16425 else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint16_t>::max)()))
16426 {
16427 if (add_prefix)
16428 {
16429 oa->write_character(to_char_type('u')); // uint16 - bjdata only
16430 }
16431 write_number(static_cast<std::uint16_t>(n), use_bjdata);
16432 }
16433 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
16434 {
16435 if (add_prefix)
16436 {
16437 oa->write_character(to_char_type('l')); // int32
16438 }
16439 write_number(static_cast<std::int32_t>(n), use_bjdata);
16440 }
16441 else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint32_t>::max)()))
16442 {
16443 if (add_prefix)
16444 {
16445 oa->write_character(to_char_type('m')); // uint32 - bjdata only
16446 }
16447 write_number(static_cast<std::uint32_t>(n), use_bjdata);
16448 }
16449 else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
16450 {
16451 if (add_prefix)
16452 {
16453 oa->write_character(to_char_type('L')); // int64
16454 }
16455 write_number(static_cast<std::int64_t>(n), use_bjdata);
16456 }
16457 else if (use_bjdata && n <= (std::numeric_limits<uint64_t>::max)())
16458 {
16459 if (add_prefix)
16460 {
16461 oa->write_character(to_char_type('M')); // uint64 - bjdata only
16462 }
16463 write_number(static_cast<std::uint64_t>(n), use_bjdata);
16464 }
16465 else
16466 {
16467 if (add_prefix)
16468 {
16469 oa->write_character(to_char_type('H')); // high-precision number
16470 }
16471
16472 const auto number = BasicJsonType(n).dump();
16473 write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
16474 for (std::size_t i = 0; i < number.size(); ++i)
16475 {
16476 oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
16477 }
16478 }
16479 }
16480
16481 // UBJSON: write number (signed integer)
16482 template < typename NumberType, typename std::enable_if <
16483 std::is_signed<NumberType>::value&&
16484 !std::is_floating_point<NumberType>::value, int >::type = 0 >
16485 void write_number_with_ubjson_prefix(const NumberType n,
16486 const bool add_prefix,
16487 const bool use_bjdata)
16488 {
16489 if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())
16490 {
16491 if (add_prefix)
16492 {
16493 oa->write_character(to_char_type('i')); // int8
16494 }
16495 write_number(static_cast<std::int8_t>(n), use_bjdata);
16496 }
16497 else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))
16498 {
16499 if (add_prefix)
16500 {
16501 oa->write_character(to_char_type('U')); // uint8
16502 }
16503 write_number(static_cast<std::uint8_t>(n), use_bjdata);
16504 }
16505 else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())
16506 {
16507 if (add_prefix)
16508 {
16509 oa->write_character(to_char_type('I')); // int16
16510 }
16511 write_number(static_cast<std::int16_t>(n), use_bjdata);
16512 }
16513 else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::max)())))
16514 {
16515 if (add_prefix)
16516 {
16517 oa->write_character(to_char_type('u')); // uint16 - bjdata only
16518 }
16519 write_number(static_cast<uint16_t>(n), use_bjdata);
16520 }
16521 else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())
16522 {
16523 if (add_prefix)
16524 {
16525 oa->write_character(to_char_type('l')); // int32
16526 }
16527 write_number(static_cast<std::int32_t>(n), use_bjdata);
16528 }
16529 else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::max)())))
16530 {
16531 if (add_prefix)
16532 {
16533 oa->write_character(to_char_type('m')); // uint32 - bjdata only
16534 }
16535 write_number(static_cast<uint32_t>(n), use_bjdata);
16536 }
16537 else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())
16538 {
16539 if (add_prefix)
16540 {
16541 oa->write_character(to_char_type('L')); // int64
16542 }
16543 write_number(static_cast<std::int64_t>(n), use_bjdata);
16544 }
16545 // LCOV_EXCL_START
16546 else
16547 {
16548 if (add_prefix)
16549 {
16550 oa->write_character(to_char_type('H')); // high-precision number
16551 }
16552
16553 const auto number = BasicJsonType(n).dump();
16554 write_number_with_ubjson_prefix(number.size(), true, use_bjdata);
16555 for (std::size_t i = 0; i < number.size(); ++i)
16556 {
16557 oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));
16558 }
16559 }
16560 // LCOV_EXCL_STOP
16561 }
16562
16566 CharType ubjson_prefix(const BasicJsonType& j, const bool use_bjdata) const noexcept
16567 {
16568 switch (j.type())
16569 {
16570 case value_t::null:
16571 return 'Z';
16572
16573 case value_t::boolean:
16574 return j.m_data.m_value.boolean ? 'T' : 'F';
16575
16576 case value_t::number_integer:
16577 {
16578 if ((std::numeric_limits<std::int8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
16579 {
16580 return 'i';
16581 }
16582 if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
16583 {
16584 return 'U';
16585 }
16586 if ((std::numeric_limits<std::int16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
16587 {
16588 return 'I';
16589 }
16590 if (use_bjdata && ((std::numeric_limits<std::uint16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()))
16591 {
16592 return 'u';
16593 }
16594 if ((std::numeric_limits<std::int32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
16595 {
16596 return 'l';
16597 }
16598 if (use_bjdata && ((std::numeric_limits<std::uint32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()))
16599 {
16600 return 'm';
16601 }
16602 if ((std::numeric_limits<std::int64_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
16603 {
16604 return 'L';
16605 }
16606 // anything else is treated as high-precision number
16607 return 'H'; // LCOV_EXCL_LINE
16608 }
16609
16610 case value_t::number_unsigned:
16611 {
16612 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
16613 {
16614 return 'i';
16615 }
16616 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))
16617 {
16618 return 'U';
16619 }
16620 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
16621 {
16622 return 'I';
16623 }
16624 if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint16_t>::max)()))
16625 {
16626 return 'u';
16627 }
16628 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
16629 {
16630 return 'l';
16631 }
16632 if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint32_t>::max)()))
16633 {
16634 return 'm';
16635 }
16636 if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
16637 {
16638 return 'L';
16639 }
16640 if (use_bjdata && j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
16641 {
16642 return 'M';
16643 }
16644 // anything else is treated as high-precision number
16645 return 'H'; // LCOV_EXCL_LINE
16646 }
16647
16648 case value_t::number_float:
16649 return get_ubjson_float_prefix(j.m_data.m_value.number_float);
16650
16651 case value_t::string:
16652 return 'S';
16653
16654 case value_t::array: // fallthrough
16655 case value_t::binary:
16656 return '[';
16657
16658 case value_t::object:
16659 return '{';
16660
16661 case value_t::discarded:
16662 default: // discarded values
16663 return 'N';
16664 }
16665 }
16666
16667 static constexpr CharType get_ubjson_float_prefix(float /*unused*/)
16668 {
16669 return 'd'; // float 32
16670 }
16671
16672 static constexpr CharType get_ubjson_float_prefix(double /*unused*/)
16673 {
16674 return 'D'; // float 64
16675 }
16676
16680 bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type)
16681 {
16682 std::map<string_t, CharType> bjdtype = {{"uint8", 'U'}, {"int8", 'i'}, {"uint16", 'u'}, {"int16", 'I'},
16683 {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, {"char", 'C'}
16684 };
16685
16686 string_t key = "_ArrayType_";
16687 auto it = bjdtype.find(static_cast<string_t>(value.at(key)));
16688 if (it == bjdtype.end())
16689 {
16690 return true;
16691 }
16692 CharType dtype = it->second;
16693
16694 key = "_ArraySize_";
16695 std::size_t len = (value.at(key).empty() ? 0 : 1);
16696 for (const auto& el : value.at(key))
16697 {
16698 len *= static_cast<std::size_t>(el.m_data.m_value.number_unsigned);
16699 }
16700
16701 key = "_ArrayData_";
16702 if (value.at(key).size() != len)
16703 {
16704 return true;
16705 }
16706
16707 oa->write_character('[');
16708 oa->write_character('$');
16709 oa->write_character(dtype);
16710 oa->write_character('#');
16711
16712 key = "_ArraySize_";
16713 write_ubjson(value.at(key), use_count, use_type, true, true);
16714
16715 key = "_ArrayData_";
16716 if (dtype == 'U' || dtype == 'C')
16717 {
16718 for (const auto& el : value.at(key))
16719 {
16720 write_number(static_cast<std::uint8_t>(el.m_data.m_value.number_unsigned), true);
16721 }
16722 }
16723 else if (dtype == 'i')
16724 {
16725 for (const auto& el : value.at(key))
16726 {
16727 write_number(static_cast<std::int8_t>(el.m_data.m_value.number_integer), true);
16728 }
16729 }
16730 else if (dtype == 'u')
16731 {
16732 for (const auto& el : value.at(key))
16733 {
16734 write_number(static_cast<std::uint16_t>(el.m_data.m_value.number_unsigned), true);
16735 }
16736 }
16737 else if (dtype == 'I')
16738 {
16739 for (const auto& el : value.at(key))
16740 {
16741 write_number(static_cast<std::int16_t>(el.m_data.m_value.number_integer), true);
16742 }
16743 }
16744 else if (dtype == 'm')
16745 {
16746 for (const auto& el : value.at(key))
16747 {
16748 write_number(static_cast<std::uint32_t>(el.m_data.m_value.number_unsigned), true);
16749 }
16750 }
16751 else if (dtype == 'l')
16752 {
16753 for (const auto& el : value.at(key))
16754 {
16755 write_number(static_cast<std::int32_t>(el.m_data.m_value.number_integer), true);
16756 }
16757 }
16758 else if (dtype == 'M')
16759 {
16760 for (const auto& el : value.at(key))
16761 {
16762 write_number(static_cast<std::uint64_t>(el.m_data.m_value.number_unsigned), true);
16763 }
16764 }
16765 else if (dtype == 'L')
16766 {
16767 for (const auto& el : value.at(key))
16768 {
16769 write_number(static_cast<std::int64_t>(el.m_data.m_value.number_integer), true);
16770 }
16771 }
16772 else if (dtype == 'd')
16773 {
16774 for (const auto& el : value.at(key))
16775 {
16776 write_number(static_cast<float>(el.m_data.m_value.number_float), true);
16777 }
16778 }
16779 else if (dtype == 'D')
16780 {
16781 for (const auto& el : value.at(key))
16782 {
16783 write_number(static_cast<double>(el.m_data.m_value.number_float), true);
16784 }
16785 }
16786 return false;
16787 }
16788
16790 // Utility functions //
16792
16793 /*
16794 @brief write a number to output input
16795 @param[in] n number of type @a NumberType
16796 @param[in] OutputIsLittleEndian Set to true if output data is
16797 required to be little endian
16798 @tparam NumberType the type of the number
16799
16800 @note This function needs to respect the system's endianness, because bytes
16801 in CBOR, MessagePack, and UBJSON are stored in network order (big
16802 endian) and therefore need reordering on little endian systems.
16803 On the other hand, BSON and BJData use little endian and should reorder
16804 on big endian systems.
16805 */
16806 template<typename NumberType>
16807 void write_number(const NumberType n, const bool OutputIsLittleEndian = false)
16808 {
16809 // step 1: write number to array of length NumberType
16810 std::array<CharType, sizeof(NumberType)> vec{};
16811 std::memcpy(vec.data(), &n, sizeof(NumberType));
16812
16813 // step 2: write array to output (with possible reordering)
16814 if (is_little_endian != OutputIsLittleEndian)
16815 {
16816 // reverse byte order prior to conversion if necessary
16817 std::reverse(vec.begin(), vec.end());
16818 }
16819
16820 oa->write_characters(vec.data(), sizeof(NumberType));
16821 }
16822
16823 void write_compact_float(const number_float_t n, detail::input_format_t format)
16824 {
16825#ifdef __GNUC__
16826#pragma GCC diagnostic push
16827#pragma GCC diagnostic ignored "-Wfloat-equal"
16828#endif
16829 if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
16830 static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
16831 static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))
16832 {
16833 oa->write_character(format == detail::input_format_t::cbor
16834 ? get_cbor_float_prefix(static_cast<float>(n))
16835 : get_msgpack_float_prefix(static_cast<float>(n)));
16836 write_number(static_cast<float>(n));
16837 }
16838 else
16839 {
16840 oa->write_character(format == detail::input_format_t::cbor
16841 ? get_cbor_float_prefix(n)
16842 : get_msgpack_float_prefix(n));
16843 write_number(n);
16844 }
16845#ifdef __GNUC__
16846#pragma GCC diagnostic pop
16847#endif
16848 }
16849
16850 public:
16851 // The following to_char_type functions are implement the conversion
16852 // between uint8_t and CharType. In case CharType is not unsigned,
16853 // such a conversion is required to allow values greater than 128.
16854 // See <https://github.com/nlohmann/json/issues/1286> for a discussion.
16855 template < typename C = CharType,
16856 enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >
16857 static constexpr CharType to_char_type(std::uint8_t x) noexcept
16858 {
16859 return *reinterpret_cast<char*>(&x);
16860 }
16861
16862 template < typename C = CharType,
16863 enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >
16864 static CharType to_char_type(std::uint8_t x) noexcept
16865 {
16866 static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
16867 static_assert(std::is_trivial<CharType>::value, "CharType must be trivial");
16868 CharType result;
16869 std::memcpy(&result, &x, sizeof(x));
16870 return result;
16871 }
16872
16873 template<typename C = CharType,
16874 enable_if_t<std::is_unsigned<C>::value>* = nullptr>
16875 static constexpr CharType to_char_type(std::uint8_t x) noexcept
16876 {
16877 return x;
16878 }
16879
16880 template < typename InputCharType, typename C = CharType,
16881 enable_if_t <
16882 std::is_signed<C>::value &&
16883 std::is_signed<char>::value &&
16884 std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
16885 > * = nullptr >
16886 static constexpr CharType to_char_type(InputCharType x) noexcept
16887 {
16888 return x;
16889 }
16890
16891 private:
16893 const bool is_little_endian = little_endianness();
16894
16897};
16898
16899} // namespace detail
16900NLOHMANN_JSON_NAMESPACE_END
16901
16902// #include <nlohmann/detail/output/output_adapters.hpp>
16903
16904// #include <nlohmann/detail/output/serializer.hpp>
16905// __ _____ _____ _____
16906// __| | __| | | | JSON for Modern C++
16907// | | |__ | | | | | | version 3.11.3
16908// |_____|_____|_____|_|___| https://github.com/nlohmann/json
16909//
16910// SPDX-FileCopyrightText: 2008-2009 Björn Hoehrmann <bjoern@hoehrmann.de>
16911// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
16912// SPDX-License-Identifier: MIT
16913
16914
16915
16916#include <algorithm> // reverse, remove, fill, find, none_of
16917#include <array> // array
16918#include <clocale> // localeconv, lconv
16919#include <cmath> // labs, isfinite, isnan, signbit
16920#include <cstddef> // size_t, ptrdiff_t
16921#include <cstdint> // uint8_t
16922#include <cstdio> // snprintf
16923#include <limits> // numeric_limits
16924#include <string> // string, char_traits
16925#include <iomanip> // setfill, setw
16926#include <type_traits> // is_same
16927#include <utility> // move
16928
16929// #include <nlohmann/detail/conversions/to_chars.hpp>
16930// __ _____ _____ _____
16931// __| | __| | | | JSON for Modern C++
16932// | | |__ | | | | | | version 3.11.3
16933// |_____|_____|_____|_|___| https://github.com/nlohmann/json
16934//
16935// SPDX-FileCopyrightText: 2009 Florian Loitsch <https://florian.loitsch.com/>
16936// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
16937// SPDX-License-Identifier: MIT
16938
16939
16940
16941#include <array> // array
16942#include <cmath> // signbit, isfinite
16943#include <cstdint> // intN_t, uintN_t
16944#include <cstring> // memcpy, memmove
16945#include <limits> // numeric_limits
16946#include <type_traits> // conditional
16947
16948// #include <nlohmann/detail/macro_scope.hpp>
16949
16950
16951NLOHMANN_JSON_NAMESPACE_BEGIN
16952namespace detail
16953{
16954
16974namespace dtoa_impl
16975{
16976
16977template<typename Target, typename Source>
16978Target reinterpret_bits(const Source source)
16979{
16980 static_assert(sizeof(Target) == sizeof(Source), "size mismatch");
16981
16982 Target target;
16983 std::memcpy(&target, &source, sizeof(Source));
16984 return target;
16985}
16986
16987struct diyfp // f * 2^e
16988{
16989 static constexpr int kPrecision = 64; // = q
16990
16991 std::uint64_t f = 0;
16992 int e = 0;
16993
16994 constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {}
16995
17000 static diyfp sub(const diyfp& x, const diyfp& y) noexcept
17001 {
17002 JSON_ASSERT(x.e == y.e);
17003 JSON_ASSERT(x.f >= y.f);
17004
17005 return {x.f - y.f, x.e};
17006 }
17007
17012 static diyfp mul(const diyfp& x, const diyfp& y) noexcept
17013 {
17014 static_assert(kPrecision == 64, "internal error");
17015
17016 // Computes:
17017 // f = round((x.f * y.f) / 2^q)
17018 // e = x.e + y.e + q
17019
17020 // Emulate the 64-bit * 64-bit multiplication:
17021 //
17022 // p = u * v
17023 // = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)
17024 // = (u_lo v_lo ) + 2^32 ((u_lo v_hi ) + (u_hi v_lo )) + 2^64 (u_hi v_hi )
17025 // = (p0 ) + 2^32 ((p1 ) + (p2 )) + 2^64 (p3 )
17026 // = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3 )
17027 // = (p0_lo ) + 2^32 (p0_hi + p1_lo + p2_lo ) + 2^64 (p1_hi + p2_hi + p3)
17028 // = (p0_lo ) + 2^32 (Q ) + 2^64 (H )
17029 // = (p0_lo ) + 2^32 (Q_lo + 2^32 Q_hi ) + 2^64 (H )
17030 //
17031 // (Since Q might be larger than 2^32 - 1)
17032 //
17033 // = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)
17034 //
17035 // (Q_hi + H does not overflow a 64-bit int)
17036 //
17037 // = p_lo + 2^64 p_hi
17038
17039 const std::uint64_t u_lo = x.f & 0xFFFFFFFFu;
17040 const std::uint64_t u_hi = x.f >> 32u;
17041 const std::uint64_t v_lo = y.f & 0xFFFFFFFFu;
17042 const std::uint64_t v_hi = y.f >> 32u;
17043
17044 const std::uint64_t p0 = u_lo * v_lo;
17045 const std::uint64_t p1 = u_lo * v_hi;
17046 const std::uint64_t p2 = u_hi * v_lo;
17047 const std::uint64_t p3 = u_hi * v_hi;
17048
17049 const std::uint64_t p0_hi = p0 >> 32u;
17050 const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu;
17051 const std::uint64_t p1_hi = p1 >> 32u;
17052 const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu;
17053 const std::uint64_t p2_hi = p2 >> 32u;
17054
17055 std::uint64_t Q = p0_hi + p1_lo + p2_lo;
17056
17057 // The full product might now be computed as
17058 //
17059 // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)
17060 // p_lo = p0_lo + (Q << 32)
17061 //
17062 // But in this particular case here, the full p_lo is not required.
17063 // Effectively we only need to add the highest bit in p_lo to p_hi (and
17064 // Q_hi + 1 does not overflow).
17065
17066 Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up
17067
17068 const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);
17069
17070 return {h, x.e + y.e + 64};
17071 }
17072
17077 static diyfp normalize(diyfp x) noexcept
17078 {
17079 JSON_ASSERT(x.f != 0);
17080
17081 while ((x.f >> 63u) == 0)
17082 {
17083 x.f <<= 1u;
17084 x.e--;
17085 }
17086
17087 return x;
17088 }
17089
17094 static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept
17095 {
17096 const int delta = x.e - target_exponent;
17097
17098 JSON_ASSERT(delta >= 0);
17099 JSON_ASSERT(((x.f << delta) >> delta) == x.f);
17100
17101 return {x.f << delta, target_exponent};
17102 }
17103};
17104
17106{
17107 diyfp w;
17108 diyfp minus;
17109 diyfp plus;
17110};
17111
17118template<typename FloatType>
17120{
17121 JSON_ASSERT(std::isfinite(value));
17122 JSON_ASSERT(value > 0);
17123
17124 // Convert the IEEE representation into a diyfp.
17125 //
17126 // If v is denormal:
17127 // value = 0.F * 2^(1 - bias) = ( F) * 2^(1 - bias - (p-1))
17128 // If v is normalized:
17129 // value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))
17130
17131 static_assert(std::numeric_limits<FloatType>::is_iec559,
17132 "internal error: dtoa_short requires an IEEE-754 floating-point implementation");
17133
17134 constexpr int kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)
17135 constexpr int kBias = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);
17136 constexpr int kMinExp = 1 - kBias;
17137 constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1)
17138
17139 using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type;
17140
17141 const auto bits = static_cast<std::uint64_t>(reinterpret_bits<bits_type>(value));
17142 const std::uint64_t E = bits >> (kPrecision - 1);
17143 const std::uint64_t F = bits & (kHiddenBit - 1);
17144
17145 const bool is_denormal = E == 0;
17146 const diyfp v = is_denormal
17147 ? diyfp(F, kMinExp)
17148 : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
17149
17150 // Compute the boundaries m- and m+ of the floating-point value
17151 // v = f * 2^e.
17152 //
17153 // Determine v- and v+, the floating-point predecessor and successor if v,
17154 // respectively.
17155 //
17156 // v- = v - 2^e if f != 2^(p-1) or e == e_min (A)
17157 // = v - 2^(e-1) if f == 2^(p-1) and e > e_min (B)
17158 //
17159 // v+ = v + 2^e
17160 //
17161 // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_
17162 // between m- and m+ round to v, regardless of how the input rounding
17163 // algorithm breaks ties.
17164 //
17165 // ---+-------------+-------------+-------------+-------------+--- (A)
17166 // v- m- v m+ v+
17167 //
17168 // -----------------+------+------+-------------+-------------+--- (B)
17169 // v- m- v m+ v+
17170
17171 const bool lower_boundary_is_closer = F == 0 && E > 1;
17172 const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
17173 const diyfp m_minus = lower_boundary_is_closer
17174 ? diyfp(4 * v.f - 1, v.e - 2) // (B)
17175 : diyfp(2 * v.f - 1, v.e - 1); // (A)
17176
17177 // Determine the normalized w+ = m+.
17178 const diyfp w_plus = diyfp::normalize(m_plus);
17179
17180 // Determine w- = m- such that e_(w-) = e_(w+).
17181 const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);
17182
17183 return {diyfp::normalize(v), w_minus, w_plus};
17184}
17185
17186// Given normalized diyfp w, Grisu needs to find a (normalized) cached
17187// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies
17188// within a certain range [alpha, gamma] (Definition 3.2 from [1])
17189//
17190// alpha <= e = e_c + e_w + q <= gamma
17191//
17192// or
17193//
17194// f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q
17195// <= f_c * f_w * 2^gamma
17196//
17197// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies
17198//
17199// 2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma
17200//
17201// or
17202//
17203// 2^(q - 2 + alpha) <= c * w < 2^(q + gamma)
17204//
17205// The choice of (alpha,gamma) determines the size of the table and the form of
17206// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well
17207// in practice:
17208//
17209// The idea is to cut the number c * w = f * 2^e into two parts, which can be
17210// processed independently: An integral part p1, and a fractional part p2:
17211//
17212// f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e
17213// = (f div 2^-e) + (f mod 2^-e) * 2^e
17214// = p1 + p2 * 2^e
17215//
17216// The conversion of p1 into decimal form requires a series of divisions and
17217// modulos by (a power of) 10. These operations are faster for 32-bit than for
17218// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be
17219// achieved by choosing
17220//
17221// -e >= 32 or e <= -32 := gamma
17222//
17223// In order to convert the fractional part
17224//
17225// p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...
17226//
17227// into decimal form, the fraction is repeatedly multiplied by 10 and the digits
17228// d[-i] are extracted in order:
17229//
17230// (10 * p2) div 2^-e = d[-1]
17231// (10 * p2) mod 2^-e = d[-2] / 10^1 + ...
17232//
17233// The multiplication by 10 must not overflow. It is sufficient to choose
17234//
17235// 10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.
17236//
17237// Since p2 = f mod 2^-e < 2^-e,
17238//
17239// -e <= 60 or e >= -60 := alpha
17240
17241constexpr int kAlpha = -60;
17242constexpr int kGamma = -32;
17243
17244struct cached_power // c = f * 2^e ~= 10^k
17245{
17246 std::uint64_t f;
17247 int e;
17248 int k;
17249};
17250
17259{
17260 // Now
17261 //
17262 // alpha <= e_c + e + q <= gamma (1)
17263 // ==> f_c * 2^alpha <= c * 2^e * 2^q
17264 //
17265 // and since the c's are normalized, 2^(q-1) <= f_c,
17266 //
17267 // ==> 2^(q - 1 + alpha) <= c * 2^(e + q)
17268 // ==> 2^(alpha - e - 1) <= c
17269 //
17270 // If c were an exact power of ten, i.e. c = 10^k, one may determine k as
17271 //
17272 // k = ceil( log_10( 2^(alpha - e - 1) ) )
17273 // = ceil( (alpha - e - 1) * log_10(2) )
17274 //
17275 // From the paper:
17276 // "In theory the result of the procedure could be wrong since c is rounded,
17277 // and the computation itself is approximated [...]. In practice, however,
17278 // this simple function is sufficient."
17279 //
17280 // For IEEE double precision floating-point numbers converted into
17281 // normalized diyfp's w = f * 2^e, with q = 64,
17282 //
17283 // e >= -1022 (min IEEE exponent)
17284 // -52 (p - 1)
17285 // -52 (p - 1, possibly normalize denormal IEEE numbers)
17286 // -11 (normalize the diyfp)
17287 // = -1137
17288 //
17289 // and
17290 //
17291 // e <= +1023 (max IEEE exponent)
17292 // -52 (p - 1)
17293 // -11 (normalize the diyfp)
17294 // = 960
17295 //
17296 // This binary exponent range [-1137,960] results in a decimal exponent
17297 // range [-307,324]. One does not need to store a cached power for each
17298 // k in this range. For each such k it suffices to find a cached power
17299 // such that the exponent of the product lies in [alpha,gamma].
17300 // This implies that the difference of the decimal exponents of adjacent
17301 // table entries must be less than or equal to
17302 //
17303 // floor( (gamma - alpha) * log_10(2) ) = 8.
17304 //
17305 // (A smaller distance gamma-alpha would require a larger table.)
17306
17307 // NB:
17308 // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.
17309
17310 constexpr int kCachedPowersMinDecExp = -300;
17311 constexpr int kCachedPowersDecStep = 8;
17312
17313 static constexpr std::array<cached_power, 79> kCachedPowers =
17314 {
17315 {
17316 { 0xAB70FE17C79AC6CA, -1060, -300 },
17317 { 0xFF77B1FCBEBCDC4F, -1034, -292 },
17318 { 0xBE5691EF416BD60C, -1007, -284 },
17319 { 0x8DD01FAD907FFC3C, -980, -276 },
17320 { 0xD3515C2831559A83, -954, -268 },
17321 { 0x9D71AC8FADA6C9B5, -927, -260 },
17322 { 0xEA9C227723EE8BCB, -901, -252 },
17323 { 0xAECC49914078536D, -874, -244 },
17324 { 0x823C12795DB6CE57, -847, -236 },
17325 { 0xC21094364DFB5637, -821, -228 },
17326 { 0x9096EA6F3848984F, -794, -220 },
17327 { 0xD77485CB25823AC7, -768, -212 },
17328 { 0xA086CFCD97BF97F4, -741, -204 },
17329 { 0xEF340A98172AACE5, -715, -196 },
17330 { 0xB23867FB2A35B28E, -688, -188 },
17331 { 0x84C8D4DFD2C63F3B, -661, -180 },
17332 { 0xC5DD44271AD3CDBA, -635, -172 },
17333 { 0x936B9FCEBB25C996, -608, -164 },
17334 { 0xDBAC6C247D62A584, -582, -156 },
17335 { 0xA3AB66580D5FDAF6, -555, -148 },
17336 { 0xF3E2F893DEC3F126, -529, -140 },
17337 { 0xB5B5ADA8AAFF80B8, -502, -132 },
17338 { 0x87625F056C7C4A8B, -475, -124 },
17339 { 0xC9BCFF6034C13053, -449, -116 },
17340 { 0x964E858C91BA2655, -422, -108 },
17341 { 0xDFF9772470297EBD, -396, -100 },
17342 { 0xA6DFBD9FB8E5B88F, -369, -92 },
17343 { 0xF8A95FCF88747D94, -343, -84 },
17344 { 0xB94470938FA89BCF, -316, -76 },
17345 { 0x8A08F0F8BF0F156B, -289, -68 },
17346 { 0xCDB02555653131B6, -263, -60 },
17347 { 0x993FE2C6D07B7FAC, -236, -52 },
17348 { 0xE45C10C42A2B3B06, -210, -44 },
17349 { 0xAA242499697392D3, -183, -36 },
17350 { 0xFD87B5F28300CA0E, -157, -28 },
17351 { 0xBCE5086492111AEB, -130, -20 },
17352 { 0x8CBCCC096F5088CC, -103, -12 },
17353 { 0xD1B71758E219652C, -77, -4 },
17354 { 0x9C40000000000000, -50, 4 },
17355 { 0xE8D4A51000000000, -24, 12 },
17356 { 0xAD78EBC5AC620000, 3, 20 },
17357 { 0x813F3978F8940984, 30, 28 },
17358 { 0xC097CE7BC90715B3, 56, 36 },
17359 { 0x8F7E32CE7BEA5C70, 83, 44 },
17360 { 0xD5D238A4ABE98068, 109, 52 },
17361 { 0x9F4F2726179A2245, 136, 60 },
17362 { 0xED63A231D4C4FB27, 162, 68 },
17363 { 0xB0DE65388CC8ADA8, 189, 76 },
17364 { 0x83C7088E1AAB65DB, 216, 84 },
17365 { 0xC45D1DF942711D9A, 242, 92 },
17366 { 0x924D692CA61BE758, 269, 100 },
17367 { 0xDA01EE641A708DEA, 295, 108 },
17368 { 0xA26DA3999AEF774A, 322, 116 },
17369 { 0xF209787BB47D6B85, 348, 124 },
17370 { 0xB454E4A179DD1877, 375, 132 },
17371 { 0x865B86925B9BC5C2, 402, 140 },
17372 { 0xC83553C5C8965D3D, 428, 148 },
17373 { 0x952AB45CFA97A0B3, 455, 156 },
17374 { 0xDE469FBD99A05FE3, 481, 164 },
17375 { 0xA59BC234DB398C25, 508, 172 },
17376 { 0xF6C69A72A3989F5C, 534, 180 },
17377 { 0xB7DCBF5354E9BECE, 561, 188 },
17378 { 0x88FCF317F22241E2, 588, 196 },
17379 { 0xCC20CE9BD35C78A5, 614, 204 },
17380 { 0x98165AF37B2153DF, 641, 212 },
17381 { 0xE2A0B5DC971F303A, 667, 220 },
17382 { 0xA8D9D1535CE3B396, 694, 228 },
17383 { 0xFB9B7CD9A4A7443C, 720, 236 },
17384 { 0xBB764C4CA7A44410, 747, 244 },
17385 { 0x8BAB8EEFB6409C1A, 774, 252 },
17386 { 0xD01FEF10A657842C, 800, 260 },
17387 { 0x9B10A4E5E9913129, 827, 268 },
17388 { 0xE7109BFBA19C0C9D, 853, 276 },
17389 { 0xAC2820D9623BF429, 880, 284 },
17390 { 0x80444B5E7AA7CF85, 907, 292 },
17391 { 0xBF21E44003ACDD2D, 933, 300 },
17392 { 0x8E679C2F5E44FF8F, 960, 308 },
17393 { 0xD433179D9C8CB841, 986, 316 },
17394 { 0x9E19DB92B4E31BA9, 1013, 324 },
17395 }
17396 };
17397
17398 // This computation gives exactly the same results for k as
17399 // k = ceil((kAlpha - e - 1) * 0.30102999566398114)
17400 // for |e| <= 1500, but doesn't require floating-point operations.
17401 // NB: log_10(2) ~= 78913 / 2^18
17402 JSON_ASSERT(e >= -1500);
17403 JSON_ASSERT(e <= 1500);
17404 const int f = kAlpha - e - 1;
17405 const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);
17406
17407 const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
17408 JSON_ASSERT(index >= 0);
17409 JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size());
17410
17411 const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];
17412 JSON_ASSERT(kAlpha <= cached.e + e + 64);
17413 JSON_ASSERT(kGamma >= cached.e + e + 64);
17414
17415 return cached;
17416}
17417
17422inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)
17423{
17424 // LCOV_EXCL_START
17425 if (n >= 1000000000)
17426 {
17427 pow10 = 1000000000;
17428 return 10;
17429 }
17430 // LCOV_EXCL_STOP
17431 if (n >= 100000000)
17432 {
17433 pow10 = 100000000;
17434 return 9;
17435 }
17436 if (n >= 10000000)
17437 {
17438 pow10 = 10000000;
17439 return 8;
17440 }
17441 if (n >= 1000000)
17442 {
17443 pow10 = 1000000;
17444 return 7;
17445 }
17446 if (n >= 100000)
17447 {
17448 pow10 = 100000;
17449 return 6;
17450 }
17451 if (n >= 10000)
17452 {
17453 pow10 = 10000;
17454 return 5;
17455 }
17456 if (n >= 1000)
17457 {
17458 pow10 = 1000;
17459 return 4;
17460 }
17461 if (n >= 100)
17462 {
17463 pow10 = 100;
17464 return 3;
17465 }
17466 if (n >= 10)
17467 {
17468 pow10 = 10;
17469 return 2;
17470 }
17471
17472 pow10 = 1;
17473 return 1;
17474}
17475
17476inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,
17477 std::uint64_t rest, std::uint64_t ten_k)
17478{
17479 JSON_ASSERT(len >= 1);
17480 JSON_ASSERT(dist <= delta);
17481 JSON_ASSERT(rest <= delta);
17482 JSON_ASSERT(ten_k > 0);
17483
17484 // <--------------------------- delta ---->
17485 // <---- dist --------->
17486 // --------------[------------------+-------------------]--------------
17487 // M- w M+
17488 //
17489 // ten_k
17490 // <------>
17491 // <---- rest ---->
17492 // --------------[------------------+----+--------------]--------------
17493 // w V
17494 // = buf * 10^k
17495 //
17496 // ten_k represents a unit-in-the-last-place in the decimal representation
17497 // stored in buf.
17498 // Decrement buf by ten_k while this takes buf closer to w.
17499
17500 // The tests are written in this order to avoid overflow in unsigned
17501 // integer arithmetic.
17502
17503 while (rest < dist
17504 && delta - rest >= ten_k
17505 && (rest + ten_k < dist || dist - rest > rest + ten_k - dist))
17506 {
17507 JSON_ASSERT(buf[len - 1] != '0');
17508 buf[len - 1]--;
17509 rest += ten_k;
17510 }
17511}
17512
17517inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
17518 diyfp M_minus, diyfp w, diyfp M_plus)
17519{
17520 static_assert(kAlpha >= -60, "internal error");
17521 static_assert(kGamma <= -32, "internal error");
17522
17523 // Generates the digits (and the exponent) of a decimal floating-point
17524 // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's
17525 // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.
17526 //
17527 // <--------------------------- delta ---->
17528 // <---- dist --------->
17529 // --------------[------------------+-------------------]--------------
17530 // M- w M+
17531 //
17532 // Grisu2 generates the digits of M+ from left to right and stops as soon as
17533 // V is in [M-,M+].
17534
17535 JSON_ASSERT(M_plus.e >= kAlpha);
17536 JSON_ASSERT(M_plus.e <= kGamma);
17537
17538 std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
17539 std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e)
17540
17541 // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):
17542 //
17543 // M+ = f * 2^e
17544 // = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e
17545 // = ((p1 ) * 2^-e + (p2 )) * 2^e
17546 // = p1 + p2 * 2^e
17547
17548 const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e);
17549
17550 auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
17551 std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e
17552
17553 // 1)
17554 //
17555 // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]
17556
17557 JSON_ASSERT(p1 > 0);
17558
17559 std::uint32_t pow10{};
17560 const int k = find_largest_pow10(p1, pow10);
17561
17562 // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)
17563 //
17564 // p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))
17565 // = (d[k-1] ) * 10^(k-1) + (p1 mod 10^(k-1))
17566 //
17567 // M+ = p1 + p2 * 2^e
17568 // = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1)) + p2 * 2^e
17569 // = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e
17570 // = d[k-1] * 10^(k-1) + ( rest) * 2^e
17571 //
17572 // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)
17573 //
17574 // p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]
17575 //
17576 // but stop as soon as
17577 //
17578 // rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e
17579
17580 int n = k;
17581 while (n > 0)
17582 {
17583 // Invariants:
17584 // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k)
17585 // pow10 = 10^(n-1) <= p1 < 10^n
17586 //
17587 const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1)
17588 const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1)
17589 //
17590 // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
17591 // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
17592 //
17593 JSON_ASSERT(d <= 9);
17594 buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
17595 //
17596 // M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
17597 //
17598 p1 = r;
17599 n--;
17600 //
17601 // M+ = buffer * 10^n + (p1 + p2 * 2^e)
17602 // pow10 = 10^n
17603 //
17604
17605 // Now check if enough digits have been generated.
17606 // Compute
17607 //
17608 // p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e
17609 //
17610 // Note:
17611 // Since rest and delta share the same exponent e, it suffices to
17612 // compare the significands.
17613 const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2;
17614 if (rest <= delta)
17615 {
17616 // V = buffer * 10^n, with M- <= V <= M+.
17617
17618 decimal_exponent += n;
17619
17620 // We may now just stop. But instead look if the buffer could be
17621 // decremented to bring V closer to w.
17622 //
17623 // pow10 = 10^n is now 1 ulp in the decimal representation V.
17624 // The rounding procedure works with diyfp's with an implicit
17625 // exponent of e.
17626 //
17627 // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e
17628 //
17629 const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e;
17630 grisu2_round(buffer, length, dist, delta, rest, ten_n);
17631
17632 return;
17633 }
17634
17635 pow10 /= 10;
17636 //
17637 // pow10 = 10^(n-1) <= p1 < 10^n
17638 // Invariants restored.
17639 }
17640
17641 // 2)
17642 //
17643 // The digits of the integral part have been generated:
17644 //
17645 // M+ = d[k-1]...d[1]d[0] + p2 * 2^e
17646 // = buffer + p2 * 2^e
17647 //
17648 // Now generate the digits of the fractional part p2 * 2^e.
17649 //
17650 // Note:
17651 // No decimal point is generated: the exponent is adjusted instead.
17652 //
17653 // p2 actually represents the fraction
17654 //
17655 // p2 * 2^e
17656 // = p2 / 2^-e
17657 // = d[-1] / 10^1 + d[-2] / 10^2 + ...
17658 //
17659 // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)
17660 //
17661 // p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m
17662 // + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)
17663 //
17664 // using
17665 //
17666 // 10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)
17667 // = ( d) * 2^-e + ( r)
17668 //
17669 // or
17670 // 10^m * p2 * 2^e = d + r * 2^e
17671 //
17672 // i.e.
17673 //
17674 // M+ = buffer + p2 * 2^e
17675 // = buffer + 10^-m * (d + r * 2^e)
17676 // = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e
17677 //
17678 // and stop as soon as 10^-m * r * 2^e <= delta * 2^e
17679
17680 JSON_ASSERT(p2 > delta);
17681
17682 int m = 0;
17683 for (;;)
17684 {
17685 // Invariant:
17686 // M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e
17687 // = buffer * 10^-m + 10^-m * (p2 ) * 2^e
17688 // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e
17689 // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
17690 //
17691 JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
17692 p2 *= 10;
17693 const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e
17694 const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
17695 //
17696 // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e
17697 // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
17698 // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
17699 //
17700 JSON_ASSERT(d <= 9);
17701 buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
17702 //
17703 // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
17704 //
17705 p2 = r;
17706 m++;
17707 //
17708 // M+ = buffer * 10^-m + 10^-m * p2 * 2^e
17709 // Invariant restored.
17710
17711 // Check if enough digits have been generated.
17712 //
17713 // 10^-m * p2 * 2^e <= delta * 2^e
17714 // p2 * 2^e <= 10^m * delta * 2^e
17715 // p2 <= 10^m * delta
17716 delta *= 10;
17717 dist *= 10;
17718 if (p2 <= delta)
17719 {
17720 break;
17721 }
17722 }
17723
17724 // V = buffer * 10^-m, with M- <= V <= M+.
17725
17726 decimal_exponent -= m;
17727
17728 // 1 ulp in the decimal representation is now 10^-m.
17729 // Since delta and dist are now scaled by 10^m, we need to do the
17730 // same with ulp in order to keep the units in sync.
17731 //
17732 // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e
17733 //
17734 const std::uint64_t ten_m = one.f;
17735 grisu2_round(buffer, length, dist, delta, p2, ten_m);
17736
17737 // By construction this algorithm generates the shortest possible decimal
17738 // number (Loitsch, Theorem 6.2) which rounds back to w.
17739 // For an input number of precision p, at least
17740 //
17741 // N = 1 + ceil(p * log_10(2))
17742 //
17743 // decimal digits are sufficient to identify all binary floating-point
17744 // numbers (Matula, "In-and-Out conversions").
17745 // This implies that the algorithm does not produce more than N decimal
17746 // digits.
17747 //
17748 // N = 17 for p = 53 (IEEE double precision)
17749 // N = 9 for p = 24 (IEEE single precision)
17750}
17751
17757JSON_HEDLEY_NON_NULL(1)
17758inline void grisu2(char* buf, int& len, int& decimal_exponent,
17759 diyfp m_minus, diyfp v, diyfp m_plus)
17760{
17761 JSON_ASSERT(m_plus.e == m_minus.e);
17762 JSON_ASSERT(m_plus.e == v.e);
17763
17764 // --------(-----------------------+-----------------------)-------- (A)
17765 // m- v m+
17766 //
17767 // --------------------(-----------+-----------------------)-------- (B)
17768 // m- v m+
17769 //
17770 // First scale v (and m- and m+) such that the exponent is in the range
17771 // [alpha, gamma].
17772
17773 const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);
17774
17775 const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k
17776
17777 // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]
17778 const diyfp w = diyfp::mul(v, c_minus_k);
17779 const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);
17780 const diyfp w_plus = diyfp::mul(m_plus, c_minus_k);
17781
17782 // ----(---+---)---------------(---+---)---------------(---+---)----
17783 // w- w w+
17784 // = c*m- = c*v = c*m+
17785 //
17786 // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and
17787 // w+ are now off by a small amount.
17788 // In fact:
17789 //
17790 // w - v * 10^k < 1 ulp
17791 //
17792 // To account for this inaccuracy, add resp. subtract 1 ulp.
17793 //
17794 // --------+---[---------------(---+---)---------------]---+--------
17795 // w- M- w M+ w+
17796 //
17797 // Now any number in [M-, M+] (bounds included) will round to w when input,
17798 // regardless of how the input rounding algorithm breaks ties.
17799 //
17800 // And digit_gen generates the shortest possible such number in [M-, M+].
17801 // Note that this does not mean that Grisu2 always generates the shortest
17802 // possible number in the interval (m-, m+).
17803 const diyfp M_minus(w_minus.f + 1, w_minus.e);
17804 const diyfp M_plus (w_plus.f - 1, w_plus.e );
17805
17806 decimal_exponent = -cached.k; // = -(-k) = k
17807
17808 grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
17809}
17810
17816template<typename FloatType>
17817JSON_HEDLEY_NON_NULL(1)
17818void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
17819{
17820 static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,
17821 "internal error: not enough precision");
17822
17823 JSON_ASSERT(std::isfinite(value));
17824 JSON_ASSERT(value > 0);
17825
17826 // If the neighbors (and boundaries) of 'value' are always computed for double-precision
17827 // numbers, all float's can be recovered using strtod (and strtof). However, the resulting
17828 // decimal representations are not exactly "short".
17829 //
17830 // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)
17831 // says "value is converted to a string as if by std::sprintf in the default ("C") locale"
17832 // and since sprintf promotes floats to doubles, I think this is exactly what 'std::to_chars'
17833 // does.
17834 // On the other hand, the documentation for 'std::to_chars' requires that "parsing the
17835 // representation using the corresponding std::from_chars function recovers value exactly". That
17836 // indicates that single precision floating-point numbers should be recovered using
17837 // 'std::strtof'.
17838 //
17839 // NB: If the neighbors are computed for single-precision numbers, there is a single float
17840 // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision
17841 // value is off by 1 ulp.
17842#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if)
17843 const boundaries w = compute_boundaries(static_cast<double>(value));
17844#else
17846#endif
17847
17848 grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);
17849}
17850
17856JSON_HEDLEY_NON_NULL(1)
17857JSON_HEDLEY_RETURNS_NON_NULL
17858inline char* append_exponent(char* buf, int e)
17859{
17860 JSON_ASSERT(e > -1000);
17861 JSON_ASSERT(e < 1000);
17862
17863 if (e < 0)
17864 {
17865 e = -e;
17866 *buf++ = '-';
17867 }
17868 else
17869 {
17870 *buf++ = '+';
17871 }
17872
17873 auto k = static_cast<std::uint32_t>(e);
17874 if (k < 10)
17875 {
17876 // Always print at least two digits in the exponent.
17877 // This is for compatibility with printf("%g").
17878 *buf++ = '0';
17879 *buf++ = static_cast<char>('0' + k);
17880 }
17881 else if (k < 100)
17882 {
17883 *buf++ = static_cast<char>('0' + k / 10);
17884 k %= 10;
17885 *buf++ = static_cast<char>('0' + k);
17886 }
17887 else
17888 {
17889 *buf++ = static_cast<char>('0' + k / 100);
17890 k %= 100;
17891 *buf++ = static_cast<char>('0' + k / 10);
17892 k %= 10;
17893 *buf++ = static_cast<char>('0' + k);
17894 }
17895
17896 return buf;
17897}
17898
17908JSON_HEDLEY_NON_NULL(1)
17909JSON_HEDLEY_RETURNS_NON_NULL
17910inline char* format_buffer(char* buf, int len, int decimal_exponent,
17911 int min_exp, int max_exp)
17912{
17913 JSON_ASSERT(min_exp < 0);
17914 JSON_ASSERT(max_exp > 0);
17915
17916 const int k = len;
17917 const int n = len + decimal_exponent;
17918
17919 // v = buf * 10^(n-k)
17920 // k is the length of the buffer (number of decimal digits)
17921 // n is the position of the decimal point relative to the start of the buffer.
17922
17923 if (k <= n && n <= max_exp)
17924 {
17925 // digits[000]
17926 // len <= max_exp + 2
17927
17928 std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k));
17929 // Make it look like a floating-point number (#362, #378)
17930 buf[n + 0] = '.';
17931 buf[n + 1] = '0';
17932 return buf + (static_cast<size_t>(n) + 2);
17933 }
17934
17935 if (0 < n && n <= max_exp)
17936 {
17937 // dig.its
17938 // len <= max_digits10 + 1
17939
17940 JSON_ASSERT(k > n);
17941
17942 std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));
17943 buf[n] = '.';
17944 return buf + (static_cast<size_t>(k) + 1U);
17945 }
17946
17947 if (min_exp < n && n <= 0)
17948 {
17949 // 0.[000]digits
17950 // len <= 2 + (-min_exp - 1) + max_digits10
17951
17952 std::memmove(buf + (2 + static_cast<size_t>(-n)), buf, static_cast<size_t>(k));
17953 buf[0] = '0';
17954 buf[1] = '.';
17955 std::memset(buf + 2, '0', static_cast<size_t>(-n));
17956 return buf + (2U + static_cast<size_t>(-n) + static_cast<size_t>(k));
17957 }
17958
17959 if (k == 1)
17960 {
17961 // dE+123
17962 // len <= 1 + 5
17963
17964 buf += 1;
17965 }
17966 else
17967 {
17968 // d.igitsE+123
17969 // len <= max_digits10 + 1 + 5
17970
17971 std::memmove(buf + 2, buf + 1, static_cast<size_t>(k) - 1);
17972 buf[1] = '.';
17973 buf += 1 + static_cast<size_t>(k);
17974 }
17975
17976 *buf++ = 'e';
17977 return append_exponent(buf, n - 1);
17978}
17979
17980} // namespace dtoa_impl
17981
17992template<typename FloatType>
17993JSON_HEDLEY_NON_NULL(1, 2)
17994JSON_HEDLEY_RETURNS_NON_NULL
17995char* to_chars(char* first, const char* last, FloatType value)
17996{
17997 static_cast<void>(last); // maybe unused - fix warning
17998 JSON_ASSERT(std::isfinite(value));
17999
18000 // Use signbit(value) instead of (value < 0) since signbit works for -0.
18001 if (std::signbit(value))
18002 {
18003 value = -value;
18004 *first++ = '-';
18005 }
18006
18007#ifdef __GNUC__
18008#pragma GCC diagnostic push
18009#pragma GCC diagnostic ignored "-Wfloat-equal"
18010#endif
18011 if (value == 0) // +-0
18012 {
18013 *first++ = '0';
18014 // Make it look like a floating-point number (#362, #378)
18015 *first++ = '.';
18016 *first++ = '0';
18017 return first;
18018 }
18019#ifdef __GNUC__
18020#pragma GCC diagnostic pop
18021#endif
18022
18023 JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);
18024
18025 // Compute v = buffer * 10^decimal_exponent.
18026 // The decimal digits are stored in the buffer, which needs to be interpreted
18027 // as an unsigned decimal integer.
18028 // len is the length of the buffer, i.e. the number of decimal digits.
18029 int len = 0;
18030 int decimal_exponent = 0;
18031 dtoa_impl::grisu2(first, len, decimal_exponent, value);
18032
18033 JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10);
18034
18035 // Format the buffer like printf("%.*g", prec, value)
18036 constexpr int kMinExp = -4;
18037 // Use digits10 here to increase compatibility with version 2.
18038 constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;
18039
18040 JSON_ASSERT(last - first >= kMaxExp + 2);
18041 JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);
18042 JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);
18043
18044 return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);
18045}
18046
18047} // namespace detail
18048NLOHMANN_JSON_NAMESPACE_END
18049
18050// #include <nlohmann/detail/exceptions.hpp>
18051
18052// #include <nlohmann/detail/macro_scope.hpp>
18053
18054// #include <nlohmann/detail/meta/cpp_future.hpp>
18055
18056// #include <nlohmann/detail/output/binary_writer.hpp>
18057
18058// #include <nlohmann/detail/output/output_adapters.hpp>
18059
18060// #include <nlohmann/detail/string_concat.hpp>
18061
18062// #include <nlohmann/detail/value_t.hpp>
18063
18064
18065NLOHMANN_JSON_NAMESPACE_BEGIN
18066namespace detail
18067{
18068
18070// serialization //
18072
18075{
18076 strict,
18077 replace,
18078 ignore
18079};
18080
18081template<typename BasicJsonType>
18083{
18084 using string_t = typename BasicJsonType::string_t;
18085 using number_float_t = typename BasicJsonType::number_float_t;
18086 using number_integer_t = typename BasicJsonType::number_integer_t;
18087 using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
18088 using binary_char_t = typename BasicJsonType::binary_t::value_type;
18089 static constexpr std::uint8_t UTF8_ACCEPT = 0;
18090 static constexpr std::uint8_t UTF8_REJECT = 1;
18091
18092 public:
18099 error_handler_t error_handler_ = error_handler_t::strict)
18100 : o(std::move(s))
18101 , loc(std::localeconv())
18102 , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))
18103 , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))
18104 , indent_char(ichar)
18105 , indent_string(512, indent_char)
18106 , error_handler(error_handler_)
18107 {}
18108
18109 // delete because of pointer members
18110 serializer(const serializer&) = delete;
18111 serializer& operator=(const serializer&) = delete;
18112 serializer(serializer&&) = delete;
18113 serializer& operator=(serializer&&) = delete;
18114 ~serializer() = default;
18115
18138 void dump(const BasicJsonType& val,
18139 const bool pretty_print,
18140 const bool ensure_ascii,
18141 const unsigned int indent_step,
18142 const unsigned int current_indent = 0)
18143 {
18144 switch (val.m_data.m_type)
18145 {
18146 case value_t::object:
18147 {
18148 if (val.m_data.m_value.object->empty())
18149 {
18150 o->write_characters("{}", 2);
18151 return;
18152 }
18153
18154 if (pretty_print)
18155 {
18156 o->write_characters("{\n", 2);
18157
18158 // variable to hold indentation for recursive calls
18159 const auto new_indent = current_indent + indent_step;
18160 if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
18161 {
18162 indent_string.resize(indent_string.size() * 2, ' ');
18163 }
18164
18165 // first n-1 elements
18166 auto i = val.m_data.m_value.object->cbegin();
18167 for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
18168 {
18169 o->write_characters(indent_string.c_str(), new_indent);
18170 o->write_character('\"');
18171 dump_escaped(i->first, ensure_ascii);
18172 o->write_characters("\": ", 3);
18173 dump(i->second, true, ensure_ascii, indent_step, new_indent);
18174 o->write_characters(",\n", 2);
18175 }
18176
18177 // last element
18178 JSON_ASSERT(i != val.m_data.m_value.object->cend());
18179 JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
18180 o->write_characters(indent_string.c_str(), new_indent);
18181 o->write_character('\"');
18182 dump_escaped(i->first, ensure_ascii);
18183 o->write_characters("\": ", 3);
18184 dump(i->second, true, ensure_ascii, indent_step, new_indent);
18185
18186 o->write_character('\n');
18187 o->write_characters(indent_string.c_str(), current_indent);
18188 o->write_character('}');
18189 }
18190 else
18191 {
18192 o->write_character('{');
18193
18194 // first n-1 elements
18195 auto i = val.m_data.m_value.object->cbegin();
18196 for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)
18197 {
18198 o->write_character('\"');
18199 dump_escaped(i->first, ensure_ascii);
18200 o->write_characters("\":", 2);
18201 dump(i->second, false, ensure_ascii, indent_step, current_indent);
18202 o->write_character(',');
18203 }
18204
18205 // last element
18206 JSON_ASSERT(i != val.m_data.m_value.object->cend());
18207 JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());
18208 o->write_character('\"');
18209 dump_escaped(i->first, ensure_ascii);
18210 o->write_characters("\":", 2);
18211 dump(i->second, false, ensure_ascii, indent_step, current_indent);
18212
18213 o->write_character('}');
18214 }
18215
18216 return;
18217 }
18218
18219 case value_t::array:
18220 {
18221 if (val.m_data.m_value.array->empty())
18222 {
18223 o->write_characters("[]", 2);
18224 return;
18225 }
18226
18227 if (pretty_print)
18228 {
18229 o->write_characters("[\n", 2);
18230
18231 // variable to hold indentation for recursive calls
18232 const auto new_indent = current_indent + indent_step;
18233 if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
18234 {
18235 indent_string.resize(indent_string.size() * 2, ' ');
18236 }
18237
18238 // first n-1 elements
18239 for (auto i = val.m_data.m_value.array->cbegin();
18240 i != val.m_data.m_value.array->cend() - 1; ++i)
18241 {
18242 o->write_characters(indent_string.c_str(), new_indent);
18243 dump(*i, true, ensure_ascii, indent_step, new_indent);
18244 o->write_characters(",\n", 2);
18245 }
18246
18247 // last element
18248 JSON_ASSERT(!val.m_data.m_value.array->empty());
18249 o->write_characters(indent_string.c_str(), new_indent);
18250 dump(val.m_data.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);
18251
18252 o->write_character('\n');
18253 o->write_characters(indent_string.c_str(), current_indent);
18254 o->write_character(']');
18255 }
18256 else
18257 {
18258 o->write_character('[');
18259
18260 // first n-1 elements
18261 for (auto i = val.m_data.m_value.array->cbegin();
18262 i != val.m_data.m_value.array->cend() - 1; ++i)
18263 {
18264 dump(*i, false, ensure_ascii, indent_step, current_indent);
18265 o->write_character(',');
18266 }
18267
18268 // last element
18269 JSON_ASSERT(!val.m_data.m_value.array->empty());
18270 dump(val.m_data.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);
18271
18272 o->write_character(']');
18273 }
18274
18275 return;
18276 }
18277
18278 case value_t::string:
18279 {
18280 o->write_character('\"');
18281 dump_escaped(*val.m_data.m_value.string, ensure_ascii);
18282 o->write_character('\"');
18283 return;
18284 }
18285
18286 case value_t::binary:
18287 {
18288 if (pretty_print)
18289 {
18290 o->write_characters("{\n", 2);
18291
18292 // variable to hold indentation for recursive calls
18293 const auto new_indent = current_indent + indent_step;
18294 if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))
18295 {
18296 indent_string.resize(indent_string.size() * 2, ' ');
18297 }
18298
18299 o->write_characters(indent_string.c_str(), new_indent);
18300
18301 o->write_characters("\"bytes\": [", 10);
18302
18303 if (!val.m_data.m_value.binary->empty())
18304 {
18305 for (auto i = val.m_data.m_value.binary->cbegin();
18306 i != val.m_data.m_value.binary->cend() - 1; ++i)
18307 {
18308 dump_integer(*i);
18309 o->write_characters(", ", 2);
18310 }
18311 dump_integer(val.m_data.m_value.binary->back());
18312 }
18313
18314 o->write_characters("],\n", 3);
18315 o->write_characters(indent_string.c_str(), new_indent);
18316
18317 o->write_characters("\"subtype\": ", 11);
18318 if (val.m_data.m_value.binary->has_subtype())
18319 {
18320 dump_integer(val.m_data.m_value.binary->subtype());
18321 }
18322 else
18323 {
18324 o->write_characters("null", 4);
18325 }
18326 o->write_character('\n');
18327 o->write_characters(indent_string.c_str(), current_indent);
18328 o->write_character('}');
18329 }
18330 else
18331 {
18332 o->write_characters("{\"bytes\":[", 10);
18333
18334 if (!val.m_data.m_value.binary->empty())
18335 {
18336 for (auto i = val.m_data.m_value.binary->cbegin();
18337 i != val.m_data.m_value.binary->cend() - 1; ++i)
18338 {
18339 dump_integer(*i);
18340 o->write_character(',');
18341 }
18342 dump_integer(val.m_data.m_value.binary->back());
18343 }
18344
18345 o->write_characters("],\"subtype\":", 12);
18346 if (val.m_data.m_value.binary->has_subtype())
18347 {
18348 dump_integer(val.m_data.m_value.binary->subtype());
18349 o->write_character('}');
18350 }
18351 else
18352 {
18353 o->write_characters("null}", 5);
18354 }
18355 }
18356 return;
18357 }
18358
18359 case value_t::boolean:
18360 {
18361 if (val.m_data.m_value.boolean)
18362 {
18363 o->write_characters("true", 4);
18364 }
18365 else
18366 {
18367 o->write_characters("false", 5);
18368 }
18369 return;
18370 }
18371
18372 case value_t::number_integer:
18373 {
18374 dump_integer(val.m_data.m_value.number_integer);
18375 return;
18376 }
18377
18378 case value_t::number_unsigned:
18379 {
18380 dump_integer(val.m_data.m_value.number_unsigned);
18381 return;
18382 }
18383
18384 case value_t::number_float:
18385 {
18386 dump_float(val.m_data.m_value.number_float);
18387 return;
18388 }
18389
18390 case value_t::discarded:
18391 {
18392 o->write_characters("<discarded>", 11);
18393 return;
18394 }
18395
18396 case value_t::null:
18397 {
18398 o->write_characters("null", 4);
18399 return;
18400 }
18401
18402 default: // LCOV_EXCL_LINE
18403 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
18404 }
18405 }
18406
18407 JSON_PRIVATE_UNLESS_TESTED:
18422 void dump_escaped(const string_t& s, const bool ensure_ascii)
18423 {
18424 std::uint32_t codepoint{};
18425 std::uint8_t state = UTF8_ACCEPT;
18426 std::size_t bytes = 0; // number of bytes written to string_buffer
18427
18428 // number of bytes written at the point of the last valid byte
18429 std::size_t bytes_after_last_accept = 0;
18430 std::size_t undumped_chars = 0;
18431
18432 for (std::size_t i = 0; i < s.size(); ++i)
18433 {
18434 const auto byte = static_cast<std::uint8_t>(s[i]);
18435
18436 switch (decode(state, codepoint, byte))
18437 {
18438 case UTF8_ACCEPT: // decode found a new code point
18439 {
18440 switch (codepoint)
18441 {
18442 case 0x08: // backspace
18443 {
18444 string_buffer[bytes++] = '\\';
18445 string_buffer[bytes++] = 'b';
18446 break;
18447 }
18448
18449 case 0x09: // horizontal tab
18450 {
18451 string_buffer[bytes++] = '\\';
18452 string_buffer[bytes++] = 't';
18453 break;
18454 }
18455
18456 case 0x0A: // newline
18457 {
18458 string_buffer[bytes++] = '\\';
18459 string_buffer[bytes++] = 'n';
18460 break;
18461 }
18462
18463 case 0x0C: // formfeed
18464 {
18465 string_buffer[bytes++] = '\\';
18466 string_buffer[bytes++] = 'f';
18467 break;
18468 }
18469
18470 case 0x0D: // carriage return
18471 {
18472 string_buffer[bytes++] = '\\';
18473 string_buffer[bytes++] = 'r';
18474 break;
18475 }
18476
18477 case 0x22: // quotation mark
18478 {
18479 string_buffer[bytes++] = '\\';
18480 string_buffer[bytes++] = '\"';
18481 break;
18482 }
18483
18484 case 0x5C: // reverse solidus
18485 {
18486 string_buffer[bytes++] = '\\';
18487 string_buffer[bytes++] = '\\';
18488 break;
18489 }
18490
18491 default:
18492 {
18493 // escape control characters (0x00..0x1F) or, if
18494 // ensure_ascii parameter is used, non-ASCII characters
18495 if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))
18496 {
18497 if (codepoint <= 0xFFFF)
18498 {
18499 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
18500 static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
18501 static_cast<std::uint16_t>(codepoint)));
18502 bytes += 6;
18503 }
18504 else
18505 {
18506 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
18507 static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
18508 static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
18509 static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
18510 bytes += 12;
18511 }
18512 }
18513 else
18514 {
18515 // copy byte to buffer (all previous bytes
18516 // been copied have in default case above)
18517 string_buffer[bytes++] = s[i];
18518 }
18519 break;
18520 }
18521 }
18522
18523 // write buffer and reset index; there must be 13 bytes
18524 // left, as this is the maximal number of bytes to be
18525 // written ("\uxxxx\uxxxx\0") for one code point
18526 if (string_buffer.size() - bytes < 13)
18527 {
18528 o->write_characters(string_buffer.data(), bytes);
18529 bytes = 0;
18530 }
18531
18532 // remember the byte position of this accept
18533 bytes_after_last_accept = bytes;
18534 undumped_chars = 0;
18535 break;
18536 }
18537
18538 case UTF8_REJECT: // decode found invalid UTF-8 byte
18539 {
18540 switch (error_handler)
18541 {
18542 case error_handler_t::strict:
18543 {
18544 JSON_THROW(type_error::create(316, concat("invalid UTF-8 byte at index ", std::to_string(i), ": 0x", hex_bytes(byte | 0)), nullptr));
18545 }
18546
18547 case error_handler_t::ignore:
18548 case error_handler_t::replace:
18549 {
18550 // in case we saw this character the first time, we
18551 // would like to read it again, because the byte
18552 // may be OK for itself, but just not OK for the
18553 // previous sequence
18554 if (undumped_chars > 0)
18555 {
18556 --i;
18557 }
18558
18559 // reset length buffer to the last accepted index;
18560 // thus removing/ignoring the invalid characters
18561 bytes = bytes_after_last_accept;
18562
18563 if (error_handler == error_handler_t::replace)
18564 {
18565 // add a replacement character
18566 if (ensure_ascii)
18567 {
18568 string_buffer[bytes++] = '\\';
18569 string_buffer[bytes++] = 'u';
18570 string_buffer[bytes++] = 'f';
18571 string_buffer[bytes++] = 'f';
18572 string_buffer[bytes++] = 'f';
18573 string_buffer[bytes++] = 'd';
18574 }
18575 else
18576 {
18577 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xEF');
18578 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF');
18579 string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD');
18580 }
18581
18582 // write buffer and reset index; there must be 13 bytes
18583 // left, as this is the maximal number of bytes to be
18584 // written ("\uxxxx\uxxxx\0") for one code point
18585 if (string_buffer.size() - bytes < 13)
18586 {
18587 o->write_characters(string_buffer.data(), bytes);
18588 bytes = 0;
18589 }
18590
18591 bytes_after_last_accept = bytes;
18592 }
18593
18594 undumped_chars = 0;
18595
18596 // continue processing the string
18597 state = UTF8_ACCEPT;
18598 break;
18599 }
18600
18601 default: // LCOV_EXCL_LINE
18602 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
18603 }
18604 break;
18605 }
18606
18607 default: // decode found yet incomplete multi-byte code point
18608 {
18609 if (!ensure_ascii)
18610 {
18611 // code point will not be escaped - copy byte to buffer
18612 string_buffer[bytes++] = s[i];
18613 }
18614 ++undumped_chars;
18615 break;
18616 }
18617 }
18618 }
18619
18620 // we finished processing the string
18621 if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))
18622 {
18623 // write buffer
18624 if (bytes > 0)
18625 {
18626 o->write_characters(string_buffer.data(), bytes);
18627 }
18628 }
18629 else
18630 {
18631 // we finish reading, but do not accept: string was incomplete
18632 switch (error_handler)
18633 {
18634 case error_handler_t::strict:
18635 {
18636 JSON_THROW(type_error::create(316, concat("incomplete UTF-8 string; last byte: 0x", hex_bytes(static_cast<std::uint8_t>(s.back() | 0))), nullptr));
18637 }
18638
18639 case error_handler_t::ignore:
18640 {
18641 // write all accepted bytes
18642 o->write_characters(string_buffer.data(), bytes_after_last_accept);
18643 break;
18644 }
18645
18646 case error_handler_t::replace:
18647 {
18648 // write all accepted bytes
18649 o->write_characters(string_buffer.data(), bytes_after_last_accept);
18650 // add a replacement character
18651 if (ensure_ascii)
18652 {
18653 o->write_characters("\\ufffd", 6);
18654 }
18655 else
18656 {
18657 o->write_characters("\xEF\xBF\xBD", 3);
18658 }
18659 break;
18660 }
18661
18662 default: // LCOV_EXCL_LINE
18663 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
18664 }
18665 }
18666 }
18667
18668 private:
18677 inline unsigned int count_digits(number_unsigned_t x) noexcept
18678 {
18679 unsigned int n_digits = 1;
18680 for (;;)
18681 {
18682 if (x < 10)
18683 {
18684 return n_digits;
18685 }
18686 if (x < 100)
18687 {
18688 return n_digits + 1;
18689 }
18690 if (x < 1000)
18691 {
18692 return n_digits + 2;
18693 }
18694 if (x < 10000)
18695 {
18696 return n_digits + 3;
18697 }
18698 x = x / 10000u;
18699 n_digits += 4;
18700 }
18701 }
18702
18708 static std::string hex_bytes(std::uint8_t byte)
18709 {
18710 std::string result = "FF";
18711 constexpr const char* nibble_to_hex = "0123456789ABCDEF";
18712 result[0] = nibble_to_hex[byte / 16];
18713 result[1] = nibble_to_hex[byte % 16];
18714 return result;
18715 }
18716
18717 // templates to avoid warnings about useless casts
18718 template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
18719 bool is_negative_number(NumberType x)
18720 {
18721 return x < 0;
18722 }
18723
18724 template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 >
18725 bool is_negative_number(NumberType /*unused*/)
18726 {
18727 return false;
18728 }
18729
18739 template < typename NumberType, detail::enable_if_t <
18740 std::is_integral<NumberType>::value ||
18741 std::is_same<NumberType, number_unsigned_t>::value ||
18742 std::is_same<NumberType, number_integer_t>::value ||
18743 std::is_same<NumberType, binary_char_t>::value,
18744 int > = 0 >
18745 void dump_integer(NumberType x)
18746 {
18747 static constexpr std::array<std::array<char, 2>, 100> digits_to_99
18748 {
18749 {
18750 {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},
18751 {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},
18752 {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},
18753 {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},
18754 {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},
18755 {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},
18756 {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},
18757 {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},
18758 {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},
18759 {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},
18760 }
18761 };
18762
18763 // special case for "0"
18764 if (x == 0)
18765 {
18766 o->write_character('0');
18767 return;
18768 }
18769
18770 // use a pointer to fill the buffer
18771 auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
18772
18773 number_unsigned_t abs_value;
18774
18775 unsigned int n_chars{};
18776
18777 if (is_negative_number(x))
18778 {
18779 *buffer_ptr = '-';
18780 abs_value = remove_sign(static_cast<number_integer_t>(x));
18781
18782 // account one more byte for the minus sign
18783 n_chars = 1 + count_digits(abs_value);
18784 }
18785 else
18786 {
18787 abs_value = static_cast<number_unsigned_t>(x);
18788 n_chars = count_digits(abs_value);
18789 }
18790
18791 // spare 1 byte for '\0'
18792 JSON_ASSERT(n_chars < number_buffer.size() - 1);
18793
18794 // jump to the end to generate the string from backward,
18795 // so we later avoid reversing the result
18796 buffer_ptr += n_chars;
18797
18798 // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu
18799 // See: https://www.youtube.com/watch?v=o4-CwDo2zpg
18800 while (abs_value >= 100)
18801 {
18802 const auto digits_index = static_cast<unsigned>((abs_value % 100));
18803 abs_value /= 100;
18804 *(--buffer_ptr) = digits_to_99[digits_index][1];
18805 *(--buffer_ptr) = digits_to_99[digits_index][0];
18806 }
18807
18808 if (abs_value >= 10)
18809 {
18810 const auto digits_index = static_cast<unsigned>(abs_value);
18811 *(--buffer_ptr) = digits_to_99[digits_index][1];
18812 *(--buffer_ptr) = digits_to_99[digits_index][0];
18813 }
18814 else
18815 {
18816 *(--buffer_ptr) = static_cast<char>('0' + abs_value);
18817 }
18818
18819 o->write_characters(number_buffer.data(), n_chars);
18820 }
18821
18830 void dump_float(number_float_t x)
18831 {
18832 // NaN / inf
18833 if (!std::isfinite(x))
18834 {
18835 o->write_characters("null", 4);
18836 return;
18837 }
18838
18839 // If number_float_t is an IEEE-754 single or double precision number,
18840 // use the Grisu2 algorithm to produce short numbers which are
18841 // guaranteed to round-trip, using strtof and strtod, resp.
18842 //
18843 // NB: The test below works if <long double> == <double>.
18844 static constexpr bool is_ieee_single_or_double
18845 = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||
18846 (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);
18847
18848 dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
18849 }
18850
18851 void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)
18852 {
18853 auto* begin = number_buffer.data();
18854 auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);
18855
18856 o->write_characters(begin, static_cast<size_t>(end - begin));
18857 }
18858
18859 void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)
18860 {
18861 // get number of digits for a float -> text -> float round-trip
18862 static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;
18863
18864 // the actual conversion
18865 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
18866 std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), "%.*g", d, x);
18867
18868 // negative value indicates an error
18869 JSON_ASSERT(len > 0);
18870 // check if buffer was large enough
18871 JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());
18872
18873 // erase thousands separator
18874 if (thousands_sep != '\0')
18875 {
18876 // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081
18877 const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep);
18878 std::fill(end, number_buffer.end(), '\0');
18879 JSON_ASSERT((end - number_buffer.begin()) <= len);
18880 len = (end - number_buffer.begin());
18881 }
18882
18883 // convert decimal point to '.'
18884 if (decimal_point != '\0' && decimal_point != '.')
18885 {
18886 // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081
18887 const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);
18888 if (dec_pos != number_buffer.end())
18889 {
18890 *dec_pos = '.';
18891 }
18892 }
18893
18894 o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));
18895
18896 // determine if we need to append ".0"
18897 const bool value_is_int_like =
18898 std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,
18899 [](char c)
18900 {
18901 return c == '.' || c == 'e';
18902 });
18903
18904 if (value_is_int_like)
18905 {
18906 o->write_characters(".0", 2);
18907 }
18908 }
18909
18931 static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept
18932 {
18933 static const std::array<std::uint8_t, 400> utf8d =
18934 {
18935 {
18936 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F
18937 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F
18938 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F
18939 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F
18940 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F
18941 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF
18942 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF
18943 0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF
18944 0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF
18945 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
18946 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
18947 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
18948 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
18949 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8
18950 }
18951 };
18952
18953 JSON_ASSERT(byte < utf8d.size());
18954 const std::uint8_t type = utf8d[byte];
18955
18956 codep = (state != UTF8_ACCEPT)
18957 ? (byte & 0x3fu) | (codep << 6u)
18958 : (0xFFu >> type) & (byte);
18959
18960 const std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
18961 JSON_ASSERT(index < utf8d.size());
18962 state = utf8d[index];
18963 return state;
18964 }
18965
18966 /*
18967 * Overload to make the compiler happy while it is instantiating
18968 * dump_integer for number_unsigned_t.
18969 * Must never be called.
18970 */
18971 number_unsigned_t remove_sign(number_unsigned_t x)
18972 {
18973 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
18974 return x; // LCOV_EXCL_LINE
18975 }
18976
18977 /*
18978 * Helper function for dump_integer
18979 *
18980 * This function takes a negative signed integer and returns its absolute
18981 * value as unsigned integer. The plus/minus shuffling is necessary as we can
18982 * not directly remove the sign of an arbitrary signed integer as the
18983 * absolute values of INT_MIN and INT_MAX are usually not the same. See
18984 * #1708 for details.
18985 */
18986 inline number_unsigned_t remove_sign(number_integer_t x) noexcept
18987 {
18988 JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression)
18989 return static_cast<number_unsigned_t>(-(x + 1)) + 1;
18990 }
18991
18992 private:
18994 output_adapter_t<char> o = nullptr;
18995
18997 std::array<char, 64> number_buffer{{}};
18998
19000 const std::lconv* loc = nullptr;
19002 const char thousands_sep = '\0';
19004 const char decimal_point = '\0';
19005
19007 std::array<char, 512> string_buffer{{}};
19008
19010 const char indent_char;
19013
19016};
19017
19018} // namespace detail
19019NLOHMANN_JSON_NAMESPACE_END
19020
19021// #include <nlohmann/detail/value_t.hpp>
19022
19023// #include <nlohmann/json_fwd.hpp>
19024
19025// #include <nlohmann/ordered_map.hpp>
19026// __ _____ _____ _____
19027// __| | __| | | | JSON for Modern C++
19028// | | |__ | | | | | | version 3.11.3
19029// |_____|_____|_____|_|___| https://github.com/nlohmann/json
19030//
19031// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
19032// SPDX-License-Identifier: MIT
19033
19034
19035
19036#include <functional> // equal_to, less
19037#include <initializer_list> // initializer_list
19038#include <iterator> // input_iterator_tag, iterator_traits
19039#include <memory> // allocator
19040#include <stdexcept> // for out_of_range
19041#include <type_traits> // enable_if, is_convertible
19042#include <utility> // pair
19043#include <vector> // vector
19044
19045// #include <nlohmann/detail/macro_scope.hpp>
19046
19047// #include <nlohmann/detail/meta/type_traits.hpp>
19048
19049
19050NLOHMANN_JSON_NAMESPACE_BEGIN
19051
19054template <class Key, class T, class IgnoredLess = std::less<Key>,
19055 class Allocator = std::allocator<std::pair<const Key, T>>>
19056 struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>
19057{
19058 using key_type = Key;
19059 using mapped_type = T;
19060 using Container = std::vector<std::pair<const Key, T>, Allocator>;
19061 using iterator = typename Container::iterator;
19062 using const_iterator = typename Container::const_iterator;
19063 using size_type = typename Container::size_type;
19064 using value_type = typename Container::value_type;
19065#ifdef JSON_HAS_CPP_14
19066 using key_compare = std::equal_to<>;
19067#else
19068 using key_compare = std::equal_to<Key>;
19069#endif
19070
19071 // Explicit constructors instead of `using Container::Container`
19072 // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
19073 ordered_map() noexcept(noexcept(Container())) : Container{} {}
19074 explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {}
19075 template <class It>
19076 ordered_map(It first, It last, const Allocator& alloc = Allocator())
19077 : Container{first, last, alloc} {}
19078 ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() )
19079 : Container{init, alloc} {}
19080
19081 std::pair<iterator, bool> emplace(const key_type& key, T&& t)
19082 {
19083 for (auto it = this->begin(); it != this->end(); ++it)
19084 {
19085 if (m_compare(it->first, key))
19086 {
19087 return {it, false};
19088 }
19089 }
19090 Container::emplace_back(key, std::forward<T>(t));
19091 return {std::prev(this->end()), true};
19092 }
19093
19094 template<class KeyType, detail::enable_if_t<
19095 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19096 std::pair<iterator, bool> emplace(KeyType && key, T && t)
19097 {
19098 for (auto it = this->begin(); it != this->end(); ++it)
19099 {
19100 if (m_compare(it->first, key))
19101 {
19102 return {it, false};
19103 }
19104 }
19105 Container::emplace_back(std::forward<KeyType>(key), std::forward<T>(t));
19106 return {std::prev(this->end()), true};
19107 }
19108
19109 T& operator[](const key_type& key)
19110 {
19111 return emplace(key, T{}).first->second;
19112 }
19113
19114 template<class KeyType, detail::enable_if_t<
19115 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19116 T & operator[](KeyType && key)
19117 {
19118 return emplace(std::forward<KeyType>(key), T{}).first->second;
19119 }
19120
19121 const T& operator[](const key_type& key) const
19122 {
19123 return at(key);
19124 }
19125
19126 template<class KeyType, detail::enable_if_t<
19127 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19128 const T & operator[](KeyType && key) const
19129 {
19130 return at(std::forward<KeyType>(key));
19131 }
19132
19133 T& at(const key_type& key)
19134 {
19135 for (auto it = this->begin(); it != this->end(); ++it)
19136 {
19137 if (m_compare(it->first, key))
19138 {
19139 return it->second;
19140 }
19141 }
19142
19143 JSON_THROW(std::out_of_range("key not found"));
19144 }
19145
19146 template<class KeyType, detail::enable_if_t<
19147 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19148 T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
19149 {
19150 for (auto it = this->begin(); it != this->end(); ++it)
19151 {
19152 if (m_compare(it->first, key))
19153 {
19154 return it->second;
19155 }
19156 }
19157
19158 JSON_THROW(std::out_of_range("key not found"));
19159 }
19160
19161 const T& at(const key_type& key) const
19162 {
19163 for (auto it = this->begin(); it != this->end(); ++it)
19164 {
19165 if (m_compare(it->first, key))
19166 {
19167 return it->second;
19168 }
19169 }
19170
19171 JSON_THROW(std::out_of_range("key not found"));
19172 }
19173
19174 template<class KeyType, detail::enable_if_t<
19175 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19176 const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
19177 {
19178 for (auto it = this->begin(); it != this->end(); ++it)
19179 {
19180 if (m_compare(it->first, key))
19181 {
19182 return it->second;
19183 }
19184 }
19185
19186 JSON_THROW(std::out_of_range("key not found"));
19187 }
19188
19189 size_type erase(const key_type& key)
19190 {
19191 for (auto it = this->begin(); it != this->end(); ++it)
19192 {
19193 if (m_compare(it->first, key))
19194 {
19195 // Since we cannot move const Keys, re-construct them in place
19196 for (auto next = it; ++next != this->end(); ++it)
19197 {
19198 it->~value_type(); // Destroy but keep allocation
19199 new (&*it) value_type{std::move(*next)};
19200 }
19201 Container::pop_back();
19202 return 1;
19203 }
19204 }
19205 return 0;
19206 }
19207
19208 template<class KeyType, detail::enable_if_t<
19209 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19210 size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
19211 {
19212 for (auto it = this->begin(); it != this->end(); ++it)
19213 {
19214 if (m_compare(it->first, key))
19215 {
19216 // Since we cannot move const Keys, re-construct them in place
19217 for (auto next = it; ++next != this->end(); ++it)
19218 {
19219 it->~value_type(); // Destroy but keep allocation
19220 new (&*it) value_type{std::move(*next)};
19221 }
19222 Container::pop_back();
19223 return 1;
19224 }
19225 }
19226 return 0;
19227 }
19228
19229 iterator erase(iterator pos)
19230 {
19231 return erase(pos, std::next(pos));
19232 }
19233
19234 iterator erase(iterator first, iterator last)
19235 {
19236 if (first == last)
19237 {
19238 return first;
19239 }
19240
19241 const auto elements_affected = std::distance(first, last);
19242 const auto offset = std::distance(Container::begin(), first);
19243
19244 // This is the start situation. We need to delete elements_affected
19245 // elements (3 in this example: e, f, g), and need to return an
19246 // iterator past the last deleted element (h in this example).
19247 // Note that offset is the distance from the start of the vector
19248 // to first. We will need this later.
19249
19250 // [ a, b, c, d, e, f, g, h, i, j ]
19251 // ^ ^
19252 // first last
19253
19254 // Since we cannot move const Keys, we re-construct them in place.
19255 // We start at first and re-construct (viz. copy) the elements from
19256 // the back of the vector. Example for first iteration:
19257
19258 // ,--------.
19259 // v | destroy e and re-construct with h
19260 // [ a, b, c, d, e, f, g, h, i, j ]
19261 // ^ ^
19262 // it it + elements_affected
19263
19264 for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it)
19265 {
19266 it->~value_type(); // destroy but keep allocation
19267 new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it
19268 }
19269
19270 // [ a, b, c, d, h, i, j, h, i, j ]
19271 // ^ ^
19272 // first last
19273
19274 // remove the unneeded elements at the end of the vector
19275 Container::resize(this->size() - static_cast<size_type>(elements_affected));
19276
19277 // [ a, b, c, d, h, i, j ]
19278 // ^ ^
19279 // first last
19280
19281 // first is now pointing past the last deleted element, but we cannot
19282 // use this iterator, because it may have been invalidated by the
19283 // resize call. Instead, we can return begin() + offset.
19284 return Container::begin() + offset;
19285 }
19286
19287 size_type count(const key_type& key) const
19288 {
19289 for (auto it = this->begin(); it != this->end(); ++it)
19290 {
19291 if (m_compare(it->first, key))
19292 {
19293 return 1;
19294 }
19295 }
19296 return 0;
19297 }
19298
19299 template<class KeyType, detail::enable_if_t<
19300 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19301 size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
19302 {
19303 for (auto it = this->begin(); it != this->end(); ++it)
19304 {
19305 if (m_compare(it->first, key))
19306 {
19307 return 1;
19308 }
19309 }
19310 return 0;
19311 }
19312
19313 iterator find(const key_type& key)
19314 {
19315 for (auto it = this->begin(); it != this->end(); ++it)
19316 {
19317 if (m_compare(it->first, key))
19318 {
19319 return it;
19320 }
19321 }
19322 return Container::end();
19323 }
19324
19325 template<class KeyType, detail::enable_if_t<
19326 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
19327 iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
19328 {
19329 for (auto it = this->begin(); it != this->end(); ++it)
19330 {
19331 if (m_compare(it->first, key))
19332 {
19333 return it;
19334 }
19335 }
19336 return Container::end();
19337 }
19338
19339 const_iterator find(const key_type& key) const
19340 {
19341 for (auto it = this->begin(); it != this->end(); ++it)
19342 {
19343 if (m_compare(it->first, key))
19344 {
19345 return it;
19346 }
19347 }
19348 return Container::end();
19349 }
19350
19351 std::pair<iterator, bool> insert( value_type&& value )
19352 {
19353 return emplace(value.first, std::move(value.second));
19354 }
19355
19356 std::pair<iterator, bool> insert( const value_type& value )
19357 {
19358 for (auto it = this->begin(); it != this->end(); ++it)
19359 {
19360 if (m_compare(it->first, value.first))
19361 {
19362 return {it, false};
19363 }
19364 }
19365 Container::push_back(value);
19366 return {--this->end(), true};
19367 }
19368
19369 template<typename InputIt>
19370 using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,
19371 std::input_iterator_tag>::value>::type;
19372
19373 template<typename InputIt, typename = require_input_iter<InputIt>>
19374 void insert(InputIt first, InputIt last)
19375 {
19376 for (auto it = first; it != last; ++it)
19377 {
19378 insert(*it);
19379 }
19380 }
19381
19382private:
19383 JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare();
19384};
19385
19386NLOHMANN_JSON_NAMESPACE_END
19387
19388
19389#if defined(JSON_HAS_CPP_17)
19390 #if JSON_HAS_STATIC_RTTI
19391 #include <any>
19392 #endif
19393 #include <string_view>
19394#endif
19395
19401NLOHMANN_JSON_NAMESPACE_BEGIN
19402
19421NLOHMANN_BASIC_JSON_TPL_DECLARATION
19422class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
19423 : public ::nlohmann::detail::json_base_class<CustomBaseClass>
19424{
19425 private:
19426 template<detail::value_t> friend struct detail::external_constructor;
19427
19428 template<typename>
19429 friend class ::nlohmann::json_pointer;
19430 // can be restored when json_pointer backwards compatibility is removed
19431 // friend ::nlohmann::json_pointer<StringType>;
19432
19433 template<typename BasicJsonType, typename InputType>
19434 friend class ::nlohmann::detail::parser;
19435 friend ::nlohmann::detail::serializer<basic_json>;
19436 template<typename BasicJsonType>
19437 friend class ::nlohmann::detail::iter_impl;
19438 template<typename BasicJsonType, typename CharType>
19439 friend class ::nlohmann::detail::binary_writer;
19440 template<typename BasicJsonType, typename InputType, typename SAX>
19441 friend class ::nlohmann::detail::binary_reader;
19442 template<typename BasicJsonType>
19443 friend class ::nlohmann::detail::json_sax_dom_parser;
19444 template<typename BasicJsonType>
19445 friend class ::nlohmann::detail::json_sax_dom_callback_parser;
19446 friend class ::nlohmann::detail::exception;
19447
19449 using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
19450 using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>;
19451
19452 JSON_PRIVATE_UNLESS_TESTED:
19453 // convenience aliases for types residing in namespace detail;
19454 using lexer = ::nlohmann::detail::lexer_base<basic_json>;
19455
19456 template<typename InputAdapterType>
19457 static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser(
19458 InputAdapterType adapter,
19459 detail::parser_callback_t<basic_json>cb = nullptr,
19460 const bool allow_exceptions = true,
19461 const bool ignore_comments = false
19462 )
19463 {
19464 return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),
19465 std::move(cb), allow_exceptions, ignore_comments);
19466 }
19467
19468 private:
19469 using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;
19470 template<typename BasicJsonType>
19471 using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;
19472 template<typename BasicJsonType>
19473 using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;
19474 template<typename Iterator>
19475 using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;
19476 template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;
19477
19478 template<typename CharType>
19479 using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;
19480
19481 template<typename InputType>
19482 using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>;
19483 template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;
19484
19485 JSON_PRIVATE_UNLESS_TESTED:
19486 using serializer = ::nlohmann::detail::serializer<basic_json>;
19487
19488 public:
19489 using value_t = detail::value_t;
19491 using json_pointer = ::nlohmann::json_pointer<StringType>;
19492 template<typename T, typename SFINAE>
19493 using json_serializer = JSONSerializer<T, SFINAE>;
19499 using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
19500
19504
19506 // exceptions //
19508
19512
19519
19521
19523 // container types //
19525
19530
19533
19538
19540 using difference_type = std::ptrdiff_t;
19542 using size_type = std::size_t;
19543
19545 using allocator_type = AllocatorType<basic_json>;
19546
19548 using pointer = typename std::allocator_traits<allocator_type>::pointer;
19550 using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
19551
19553 using iterator = iter_impl<basic_json>;
19555 using const_iterator = iter_impl<const basic_json>;
19557 using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;
19559 using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;
19560
19562
19566 {
19567 return allocator_type();
19568 }
19569
19572 JSON_HEDLEY_WARN_UNUSED_RESULT
19574 {
19575 basic_json result;
19576
19577 result["copyright"] = "(C) 2013-2023 Niels Lohmann";
19578 result["name"] = "JSON for Modern C++";
19579 result["url"] = "https://github.com/nlohmann/json";
19580 result["version"]["string"] =
19581 detail::concat(std::to_string(NLOHMANN_JSON_VERSION_MAJOR), '.',
19582 std::to_string(NLOHMANN_JSON_VERSION_MINOR), '.',
19583 std::to_string(NLOHMANN_JSON_VERSION_PATCH));
19584 result["version"]["major"] = NLOHMANN_JSON_VERSION_MAJOR;
19585 result["version"]["minor"] = NLOHMANN_JSON_VERSION_MINOR;
19586 result["version"]["patch"] = NLOHMANN_JSON_VERSION_PATCH;
19587
19588#ifdef _WIN32
19589 result["platform"] = "win32";
19590#elif defined __linux__
19591 result["platform"] = "linux";
19592#elif defined __APPLE__
19593 result["platform"] = "apple";
19594#elif defined __unix__
19595 result["platform"] = "unix";
19596#else
19597 result["platform"] = "unknown";
19598#endif
19599
19600#if defined(__ICC) || defined(__INTEL_COMPILER)
19601 result["compiler"] = {{"family", "icc"}, {"version", __INTEL_COMPILER}};
19602#elif defined(__clang__)
19603 result["compiler"] = {{"family", "clang"}, {"version", __clang_version__}};
19604#elif defined(__GNUC__) || defined(__GNUG__)
19605 result["compiler"] = {{"family", "gcc"}, {"version", detail::concat(
19606 std::to_string(__GNUC__), '.',
19607 std::to_string(__GNUC_MINOR__), '.',
19608 std::to_string(__GNUC_PATCHLEVEL__))
19609 }
19610 };
19611#elif defined(__HP_cc) || defined(__HP_aCC)
19612 result["compiler"] = "hp"
19613#elif defined(__IBMCPP__)
19614 result["compiler"] = {{"family", "ilecpp"}, {"version", __IBMCPP__}};
19615#elif defined(_MSC_VER)
19616 result["compiler"] = {{"family", "msvc"}, {"version", _MSC_VER}};
19617#elif defined(__PGI)
19618 result["compiler"] = {{"family", "pgcpp"}, {"version", __PGI}};
19619#elif defined(__SUNPRO_CC)
19620 result["compiler"] = {{"family", "sunpro"}, {"version", __SUNPRO_CC}};
19621#else
19622 result["compiler"] = {{"family", "unknown"}, {"version", "unknown"}};
19623#endif
19624
19625#if defined(_MSVC_LANG)
19626 result["compiler"]["c++"] = std::to_string(_MSVC_LANG);
19627#elif defined(__cplusplus)
19628 result["compiler"]["c++"] = std::to_string(__cplusplus);
19629#else
19630 result["compiler"]["c++"] = "unknown";
19631#endif
19632 return result;
19633 }
19634
19636 // JSON value data types //
19638
19643
19648#if defined(JSON_HAS_CPP_14)
19649 // use of transparent comparator avoids unnecessary repeated construction of temporaries
19650 // in functions involving lookup by key with types other than object_t::key_type (aka. StringType)
19651 using default_object_comparator_t = std::less<>;
19652#else
19653 using default_object_comparator_t = std::less<StringType>;
19654#endif
19655
19658 using object_t = ObjectType<StringType,
19659 basic_json,
19661 AllocatorType<std::pair<const StringType,
19662 basic_json>>>;
19663
19666 using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;
19667
19670 using string_t = StringType;
19671
19674 using boolean_t = BooleanType;
19675
19678 using number_integer_t = NumberIntegerType;
19679
19682 using number_unsigned_t = NumberUnsignedType;
19683
19686 using number_float_t = NumberFloatType;
19687
19690 using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;
19691
19694 using object_comparator_t = detail::actual_object_comparator_t<basic_json>;
19695
19697
19698 private:
19699
19701 template<typename T, typename... Args>
19702 JSON_HEDLEY_RETURNS_NON_NULL
19703 static T* create(Args&& ... args)
19704 {
19705 AllocatorType<T> alloc;
19706 using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;
19707
19708 auto deleter = [&](T * obj)
19709 {
19710 AllocatorTraits::deallocate(alloc, obj, 1);
19711 };
19712 std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter);
19713 AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...);
19714 JSON_ASSERT(obj != nullptr);
19715 return obj.release();
19716 }
19717
19719 // JSON value storage //
19721
19722 JSON_PRIVATE_UNLESS_TESTED:
19748 union json_value
19749 {
19751 object_t* object;
19766
19768 json_value() = default;
19770 json_value(boolean_t v) noexcept : boolean(v) {}
19772 json_value(number_integer_t v) noexcept : number_integer(v) {}
19774 json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}
19776 json_value(number_float_t v) noexcept : number_float(v) {}
19779 {
19780 switch (t)
19781 {
19782 case value_t::object:
19783 {
19784 object = create<object_t>();
19785 break;
19786 }
19787
19788 case value_t::array:
19789 {
19790 array = create<array_t>();
19791 break;
19792 }
19793
19794 case value_t::string:
19795 {
19796 string = create<string_t>("");
19797 break;
19798 }
19799
19800 case value_t::binary:
19801 {
19802 binary = create<binary_t>();
19803 break;
19804 }
19805
19806 case value_t::boolean:
19807 {
19808 boolean = static_cast<boolean_t>(false);
19809 break;
19810 }
19811
19812 case value_t::number_integer:
19813 {
19814 number_integer = static_cast<number_integer_t>(0);
19815 break;
19816 }
19817
19818 case value_t::number_unsigned:
19819 {
19820 number_unsigned = static_cast<number_unsigned_t>(0);
19821 break;
19822 }
19823
19824 case value_t::number_float:
19825 {
19826 number_float = static_cast<number_float_t>(0.0);
19827 break;
19828 }
19829
19830 case value_t::null:
19831 {
19832 object = nullptr; // silence warning, see #821
19833 break;
19834 }
19835
19836 case value_t::discarded:
19837 default:
19838 {
19839 object = nullptr; // silence warning, see #821
19840 if (JSON_HEDLEY_UNLIKELY(t == value_t::null))
19841 {
19842 JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.11.3", nullptr)); // LCOV_EXCL_LINE
19843 }
19844 break;
19845 }
19846 }
19847 }
19848
19850 json_value(const string_t& value) : string(create<string_t>(value)) {}
19851
19853 json_value(string_t&& value) : string(create<string_t>(std::move(value))) {}
19854
19856 json_value(const object_t& value) : object(create<object_t>(value)) {}
19857
19859 json_value(object_t&& value) : object(create<object_t>(std::move(value))) {}
19860
19862 json_value(const array_t& value) : array(create<array_t>(value)) {}
19863
19865 json_value(array_t&& value) : array(create<array_t>(std::move(value))) {}
19866
19868 json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {}
19869
19871 json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {}
19872
19874 json_value(const binary_t& value) : binary(create<binary_t>(value)) {}
19875
19877 json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}
19878
19879 void destroy(value_t t)
19880 {
19881 if (
19882 (t == value_t::object && object == nullptr) ||
19883 (t == value_t::array && array == nullptr) ||
19884 (t == value_t::string && string == nullptr) ||
19885 (t == value_t::binary && binary == nullptr)
19886 )
19887 {
19888 //not initialized (e.g. due to exception in the ctor)
19889 return;
19890 }
19891 if (t == value_t::array || t == value_t::object)
19892 {
19893 // flatten the current json_value to a heap-allocated stack
19894 std::vector<basic_json> stack;
19895
19896 // move the top-level items to stack
19897 if (t == value_t::array)
19898 {
19899 stack.reserve(array->size());
19900 std::move(array->begin(), array->end(), std::back_inserter(stack));
19901 }
19902 else
19903 {
19904 stack.reserve(object->size());
19905 for (auto&& it : *object)
19906 {
19907 stack.push_back(std::move(it.second));
19908 }
19909 }
19910
19911 while (!stack.empty())
19912 {
19913 // move the last item to local variable to be processed
19914 basic_json current_item(std::move(stack.back()));
19915 stack.pop_back();
19916
19917 // if current_item is array/object, move
19918 // its children to the stack to be processed later
19919 if (current_item.is_array())
19920 {
19921 std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack));
19922
19923 current_item.m_data.m_value.array->clear();
19924 }
19925 else if (current_item.is_object())
19926 {
19927 for (auto&& it : *current_item.m_data.m_value.object)
19928 {
19929 stack.push_back(std::move(it.second));
19930 }
19931
19932 current_item.m_data.m_value.object->clear();
19933 }
19934
19935 // it's now safe that current_item get destructed
19936 // since it doesn't have any children
19937 }
19938 }
19939
19940 switch (t)
19941 {
19942 case value_t::object:
19943 {
19944 AllocatorType<object_t> alloc;
19945 std::allocator_traits<decltype(alloc)>::destroy(alloc, object);
19946 std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);
19947 break;
19948 }
19949
19950 case value_t::array:
19951 {
19952 AllocatorType<array_t> alloc;
19953 std::allocator_traits<decltype(alloc)>::destroy(alloc, array);
19954 std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);
19955 break;
19956 }
19957
19958 case value_t::string:
19959 {
19960 AllocatorType<string_t> alloc;
19961 std::allocator_traits<decltype(alloc)>::destroy(alloc, string);
19962 std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);
19963 break;
19964 }
19965
19966 case value_t::binary:
19967 {
19968 AllocatorType<binary_t> alloc;
19969 std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);
19970 std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);
19971 break;
19972 }
19973
19974 case value_t::null:
19975 case value_t::boolean:
19976 case value_t::number_integer:
19977 case value_t::number_unsigned:
19978 case value_t::number_float:
19979 case value_t::discarded:
19980 default:
19981 {
19982 break;
19983 }
19984 }
19985 }
19986 };
19987
19988 private:
20007 void assert_invariant(bool check_parents = true) const noexcept
20008 {
20009 JSON_ASSERT(m_data.m_type != value_t::object || m_data.m_value.object != nullptr);
20010 JSON_ASSERT(m_data.m_type != value_t::array || m_data.m_value.array != nullptr);
20011 JSON_ASSERT(m_data.m_type != value_t::string || m_data.m_value.string != nullptr);
20012 JSON_ASSERT(m_data.m_type != value_t::binary || m_data.m_value.binary != nullptr);
20013
20014#if JSON_DIAGNOSTICS
20015 JSON_TRY
20016 {
20017 // cppcheck-suppress assertWithSideEffect
20018 JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j)
20019 {
20020 return j.m_parent == this;
20021 }));
20022 }
20023 JSON_CATCH(...) {} // LCOV_EXCL_LINE
20024#endif
20025 static_cast<void>(check_parents);
20026 }
20027
20028 void set_parents()
20029 {
20030#if JSON_DIAGNOSTICS
20031 switch (m_data.m_type)
20032 {
20033 case value_t::array:
20034 {
20035 for (auto& element : *m_data.m_value.array)
20036 {
20037 element.m_parent = this;
20038 }
20039 break;
20040 }
20041
20042 case value_t::object:
20043 {
20044 for (auto& element : *m_data.m_value.object)
20045 {
20046 element.second.m_parent = this;
20047 }
20048 break;
20049 }
20050
20051 case value_t::null:
20052 case value_t::string:
20053 case value_t::boolean:
20054 case value_t::number_integer:
20055 case value_t::number_unsigned:
20056 case value_t::number_float:
20057 case value_t::binary:
20058 case value_t::discarded:
20059 default:
20060 break;
20061 }
20062#endif
20063 }
20064
20065 iterator set_parents(iterator it, typename iterator::difference_type count_set_parents)
20066 {
20067#if JSON_DIAGNOSTICS
20068 for (typename iterator::difference_type i = 0; i < count_set_parents; ++i)
20069 {
20070 (it + i)->m_parent = this;
20071 }
20072#else
20073 static_cast<void>(count_set_parents);
20074#endif
20075 return it;
20076 }
20077
20078 reference set_parent(reference j, std::size_t old_capacity = static_cast<std::size_t>(-1))
20079 {
20080#if JSON_DIAGNOSTICS
20081 if (old_capacity != static_cast<std::size_t>(-1))
20082 {
20083 // see https://github.com/nlohmann/json/issues/2838
20084 JSON_ASSERT(type() == value_t::array);
20085 if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
20086 {
20087 // capacity has changed: update all parents
20088 set_parents();
20089 return j;
20090 }
20091 }
20092
20093 // ordered_json uses a vector internally, so pointers could have
20094 // been invalidated; see https://github.com/nlohmann/json/issues/2962
20095#ifdef JSON_HEDLEY_MSVC_VERSION
20096#pragma warning(push )
20097#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr
20098#endif
20100 {
20101 set_parents();
20102 return j;
20103 }
20104#ifdef JSON_HEDLEY_MSVC_VERSION
20105#pragma warning( pop )
20106#endif
20107
20108 j.m_parent = this;
20109#else
20110 static_cast<void>(j);
20111 static_cast<void>(old_capacity);
20112#endif
20113 return j;
20114 }
20115
20116 public:
20118 // JSON parser callback //
20120
20124
20127 using parser_callback_t = detail::parser_callback_t<basic_json>;
20128
20130 // constructors //
20132
20137
20141 : m_data(v)
20142 {
20143 assert_invariant();
20144 }
20145
20148 basic_json(std::nullptr_t = nullptr) noexcept // NOLINT(bugprone-exception-escape)
20149 : basic_json(value_t::null)
20150 {
20151 assert_invariant();
20152 }
20153
20156 template < typename CompatibleType,
20157 typename U = detail::uncvref_t<CompatibleType>,
20158 detail::enable_if_t <
20160 basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)
20161 JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),
20162 std::forward<CompatibleType>(val))))
20163 {
20164 JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));
20165 set_parents();
20166 assert_invariant();
20167 }
20168
20171 template < typename BasicJsonType,
20172 detail::enable_if_t <
20173 detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >
20174 basic_json(const BasicJsonType& val)
20175 {
20176 using other_boolean_t = typename BasicJsonType::boolean_t;
20177 using other_number_float_t = typename BasicJsonType::number_float_t;
20178 using other_number_integer_t = typename BasicJsonType::number_integer_t;
20179 using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;
20180 using other_string_t = typename BasicJsonType::string_t;
20181 using other_object_t = typename BasicJsonType::object_t;
20182 using other_array_t = typename BasicJsonType::array_t;
20183 using other_binary_t = typename BasicJsonType::binary_t;
20184
20185 switch (val.type())
20186 {
20187 case value_t::boolean:
20188 JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());
20189 break;
20190 case value_t::number_float:
20191 JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());
20192 break;
20193 case value_t::number_integer:
20194 JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());
20195 break;
20196 case value_t::number_unsigned:
20197 JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());
20198 break;
20199 case value_t::string:
20200 JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());
20201 break;
20202 case value_t::object:
20203 JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());
20204 break;
20205 case value_t::array:
20206 JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());
20207 break;
20208 case value_t::binary:
20209 JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());
20210 break;
20211 case value_t::null:
20212 *this = nullptr;
20213 break;
20214 case value_t::discarded:
20215 m_data.m_type = value_t::discarded;
20216 break;
20217 default: // LCOV_EXCL_LINE
20218 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
20219 }
20220 JSON_ASSERT(m_data.m_type == val.type());
20221 set_parents();
20222 assert_invariant();
20223 }
20224
20228 bool type_deduction = true,
20229 value_t manual_type = value_t::array)
20230 {
20231 // check if each element is an array with two elements whose first
20232 // element is a string
20233 bool is_an_object = std::all_of(init.begin(), init.end(),
20234 [](const detail::json_ref<basic_json>& element_ref)
20235 {
20236 // The cast is to ensure op[size_type] is called, bearing in mind size_type may not be int;
20237 // (many string types can be constructed from 0 via its null-pointer guise, so we get a
20238 // broken call to op[key_type], the wrong semantics and a 4804 warning on Windows)
20239 return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[static_cast<size_type>(0)].is_string();
20240 });
20241
20242 // adjust type if type deduction is not wanted
20243 if (!type_deduction)
20244 {
20245 // if array is wanted, do not create an object though possible
20246 if (manual_type == value_t::array)
20247 {
20248 is_an_object = false;
20249 }
20250
20251 // if object is wanted but impossible, throw an exception
20252 if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))
20253 {
20254 JSON_THROW(type_error::create(301, "cannot create object from initializer list", nullptr));
20255 }
20256 }
20257
20258 if (is_an_object)
20259 {
20260 // the initializer list is a list of pairs -> create object
20261 m_data.m_type = value_t::object;
20262 m_data.m_value = value_t::object;
20263
20264 for (auto& element_ref : init)
20265 {
20266 auto element = element_ref.moved_or_copied();
20267 m_data.m_value.object->emplace(
20268 std::move(*((*element.m_data.m_value.array)[0].m_data.m_value.string)),
20269 std::move((*element.m_data.m_value.array)[1]));
20270 }
20271 }
20272 else
20273 {
20274 // the initializer list describes an array -> create array
20275 m_data.m_type = value_t::array;
20276 m_data.m_value.array = create<array_t>(init.begin(), init.end());
20277 }
20278
20279 set_parents();
20280 assert_invariant();
20281 }
20282
20285 JSON_HEDLEY_WARN_UNUSED_RESULT
20286 static basic_json binary(const typename binary_t::container_type& init)
20287 {
20288 auto res = basic_json();
20289 res.m_data.m_type = value_t::binary;
20290 res.m_data.m_value = init;
20291 return res;
20292 }
20293
20296 JSON_HEDLEY_WARN_UNUSED_RESULT
20297 static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
20298 {
20299 auto res = basic_json();
20300 res.m_data.m_type = value_t::binary;
20301 res.m_data.m_value = binary_t(init, subtype);
20302 return res;
20303 }
20304
20307 JSON_HEDLEY_WARN_UNUSED_RESULT
20308 static basic_json binary(typename binary_t::container_type&& init)
20309 {
20310 auto res = basic_json();
20311 res.m_data.m_type = value_t::binary;
20312 res.m_data.m_value = std::move(init);
20313 return res;
20314 }
20315
20318 JSON_HEDLEY_WARN_UNUSED_RESULT
20319 static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
20320 {
20321 auto res = basic_json();
20322 res.m_data.m_type = value_t::binary;
20323 res.m_data.m_value = binary_t(std::move(init), subtype);
20324 return res;
20325 }
20326
20329 JSON_HEDLEY_WARN_UNUSED_RESULT
20331 {
20332 return basic_json(init, false, value_t::array);
20333 }
20334
20337 JSON_HEDLEY_WARN_UNUSED_RESULT
20339 {
20340 return basic_json(init, false, value_t::object);
20341 }
20342
20346 m_data{cnt, val}
20347 {
20348 set_parents();
20349 assert_invariant();
20350 }
20351
20354 template < class InputIT, typename std::enable_if <
20355 std::is_same<InputIT, typename basic_json_t::iterator>::value ||
20356 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >
20357 basic_json(InputIT first, InputIT last)
20358 {
20359 JSON_ASSERT(first.m_object != nullptr);
20360 JSON_ASSERT(last.m_object != nullptr);
20361
20362 // make sure iterator fits the current value
20363 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
20364 {
20365 JSON_THROW(invalid_iterator::create(201, "iterators are not compatible", nullptr));
20366 }
20367
20368 // copy type from first iterator
20369 m_data.m_type = first.m_object->m_data.m_type;
20370
20371 // check if iterator range is complete for primitive values
20372 switch (m_data.m_type)
20373 {
20374 case value_t::boolean:
20375 case value_t::number_float:
20376 case value_t::number_integer:
20377 case value_t::number_unsigned:
20378 case value_t::string:
20379 {
20380 if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()
20381 || !last.m_it.primitive_iterator.is_end()))
20382 {
20383 JSON_THROW(invalid_iterator::create(204, "iterators out of range", first.m_object));
20384 }
20385 break;
20386 }
20387
20388 case value_t::null:
20389 case value_t::object:
20390 case value_t::array:
20391 case value_t::binary:
20392 case value_t::discarded:
20393 default:
20394 break;
20395 }
20396
20397 switch (m_data.m_type)
20398 {
20399 case value_t::number_integer:
20400 {
20401 m_data.m_value.number_integer = first.m_object->m_data.m_value.number_integer;
20402 break;
20403 }
20404
20405 case value_t::number_unsigned:
20406 {
20407 m_data.m_value.number_unsigned = first.m_object->m_data.m_value.number_unsigned;
20408 break;
20409 }
20410
20411 case value_t::number_float:
20412 {
20413 m_data.m_value.number_float = first.m_object->m_data.m_value.number_float;
20414 break;
20415 }
20416
20417 case value_t::boolean:
20418 {
20419 m_data.m_value.boolean = first.m_object->m_data.m_value.boolean;
20420 break;
20421 }
20422
20423 case value_t::string:
20424 {
20425 m_data.m_value = *first.m_object->m_data.m_value.string;
20426 break;
20427 }
20428
20429 case value_t::object:
20430 {
20431 m_data.m_value.object = create<object_t>(first.m_it.object_iterator,
20432 last.m_it.object_iterator);
20433 break;
20434 }
20435
20436 case value_t::array:
20437 {
20438 m_data.m_value.array = create<array_t>(first.m_it.array_iterator,
20439 last.m_it.array_iterator);
20440 break;
20441 }
20442
20443 case value_t::binary:
20444 {
20445 m_data.m_value = *first.m_object->m_data.m_value.binary;
20446 break;
20447 }
20448
20449 case value_t::null:
20450 case value_t::discarded:
20451 default:
20452 JSON_THROW(invalid_iterator::create(206, detail::concat("cannot construct with iterators from ", first.m_object->type_name()), first.m_object));
20453 }
20454
20455 set_parents();
20456 assert_invariant();
20457 }
20458
20460 // other constructors and destructor //
20462
20463 template<typename JsonRef,
20464 detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,
20465 std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >
20466 basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {}
20467
20471 : json_base_class_t(other)
20472 {
20473 m_data.m_type = other.m_data.m_type;
20474 // check of passed value is valid
20475 other.assert_invariant();
20476
20477 switch (m_data.m_type)
20478 {
20479 case value_t::object:
20480 {
20481 m_data.m_value = *other.m_data.m_value.object;
20482 break;
20483 }
20484
20485 case value_t::array:
20486 {
20487 m_data.m_value = *other.m_data.m_value.array;
20488 break;
20489 }
20490
20491 case value_t::string:
20492 {
20493 m_data.m_value = *other.m_data.m_value.string;
20494 break;
20495 }
20496
20497 case value_t::boolean:
20498 {
20499 m_data.m_value = other.m_data.m_value.boolean;
20500 break;
20501 }
20502
20503 case value_t::number_integer:
20504 {
20505 m_data.m_value = other.m_data.m_value.number_integer;
20506 break;
20507 }
20508
20509 case value_t::number_unsigned:
20510 {
20511 m_data.m_value = other.m_data.m_value.number_unsigned;
20512 break;
20513 }
20514
20515 case value_t::number_float:
20516 {
20517 m_data.m_value = other.m_data.m_value.number_float;
20518 break;
20519 }
20520
20521 case value_t::binary:
20522 {
20523 m_data.m_value = *other.m_data.m_value.binary;
20524 break;
20525 }
20526
20527 case value_t::null:
20528 case value_t::discarded:
20529 default:
20530 break;
20531 }
20532
20533 set_parents();
20534 assert_invariant();
20535 }
20536
20539 basic_json(basic_json&& other) noexcept
20540 : json_base_class_t(std::forward<json_base_class_t>(other)),
20541 m_data(std::move(other.m_data))
20542 {
20543 // check that passed value is valid
20544 other.assert_invariant(false);
20545
20546 // invalidate payload
20547 other.m_data.m_type = value_t::null;
20548 other.m_data.m_value = {};
20549
20550 set_parents();
20551 assert_invariant();
20552 }
20553
20557 std::is_nothrow_move_constructible<value_t>::value&&
20558 std::is_nothrow_move_assignable<value_t>::value&&
20559 std::is_nothrow_move_constructible<json_value>::value&&
20560 std::is_nothrow_move_assignable<json_value>::value&&
20561 std::is_nothrow_move_assignable<json_base_class_t>::value
20562 )
20563 {
20564 // check that passed value is valid
20565 other.assert_invariant();
20566
20567 using std::swap;
20568 swap(m_data.m_type, other.m_data.m_type);
20569 swap(m_data.m_value, other.m_data.m_value);
20570 json_base_class_t::operator=(std::move(other));
20571
20572 set_parents();
20573 assert_invariant();
20574 return *this;
20575 }
20576
20579 ~basic_json() noexcept
20580 {
20581 assert_invariant(false);
20582 }
20583
20585
20586 public:
20588 // object inspection //
20590
20594
20597 string_t dump(const int indent = -1,
20598 const char indent_char = ' ',
20599 const bool ensure_ascii = false,
20600 const error_handler_t error_handler = error_handler_t::strict) const
20601 {
20602 string_t result;
20603 serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);
20604
20605 if (indent >= 0)
20606 {
20607 s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));
20608 }
20609 else
20610 {
20611 s.dump(*this, false, ensure_ascii, 0);
20612 }
20613
20614 return result;
20615 }
20616
20619 constexpr value_t type() const noexcept
20620 {
20621 return m_data.m_type;
20622 }
20623
20626 constexpr bool is_primitive() const noexcept
20627 {
20628 return is_null() || is_string() || is_boolean() || is_number() || is_binary();
20629 }
20630
20633 constexpr bool is_structured() const noexcept
20634 {
20635 return is_array() || is_object();
20636 }
20637
20640 constexpr bool is_null() const noexcept
20641 {
20642 return m_data.m_type == value_t::null;
20643 }
20644
20647 constexpr bool is_boolean() const noexcept
20648 {
20649 return m_data.m_type == value_t::boolean;
20650 }
20651
20654 constexpr bool is_number() const noexcept
20655 {
20656 return is_number_integer() || is_number_float();
20657 }
20658
20661 constexpr bool is_number_integer() const noexcept
20662 {
20663 return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned;
20664 }
20665
20668 constexpr bool is_number_unsigned() const noexcept
20669 {
20670 return m_data.m_type == value_t::number_unsigned;
20671 }
20672
20675 constexpr bool is_number_float() const noexcept
20676 {
20677 return m_data.m_type == value_t::number_float;
20678 }
20679
20682 constexpr bool is_object() const noexcept
20683 {
20684 return m_data.m_type == value_t::object;
20685 }
20686
20689 constexpr bool is_array() const noexcept
20690 {
20691 return m_data.m_type == value_t::array;
20692 }
20693
20696 constexpr bool is_string() const noexcept
20697 {
20698 return m_data.m_type == value_t::string;
20699 }
20700
20703 constexpr bool is_binary() const noexcept
20704 {
20705 return m_data.m_type == value_t::binary;
20706 }
20707
20710 constexpr bool is_discarded() const noexcept
20711 {
20712 return m_data.m_type == value_t::discarded;
20713 }
20714
20717 constexpr operator value_t() const noexcept
20718 {
20719 return m_data.m_type;
20720 }
20721
20723
20724 private:
20726 // value access //
20728
20730 boolean_t get_impl(boolean_t* /*unused*/) const
20731 {
20732 if (JSON_HEDLEY_LIKELY(is_boolean()))
20733 {
20734 return m_data.m_value.boolean;
20735 }
20736
20737 JSON_THROW(type_error::create(302, detail::concat("type must be boolean, but is ", type_name()), this));
20738 }
20739
20741 object_t* get_impl_ptr(object_t* /*unused*/) noexcept
20742 {
20743 return is_object() ? m_data.m_value.object : nullptr;
20744 }
20745
20747 constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept
20748 {
20749 return is_object() ? m_data.m_value.object : nullptr;
20750 }
20751
20753 array_t* get_impl_ptr(array_t* /*unused*/) noexcept
20754 {
20755 return is_array() ? m_data.m_value.array : nullptr;
20756 }
20757
20759 constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept
20760 {
20761 return is_array() ? m_data.m_value.array : nullptr;
20762 }
20763
20765 string_t* get_impl_ptr(string_t* /*unused*/) noexcept
20766 {
20767 return is_string() ? m_data.m_value.string : nullptr;
20768 }
20769
20771 constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept
20772 {
20773 return is_string() ? m_data.m_value.string : nullptr;
20774 }
20775
20777 boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept
20778 {
20779 return is_boolean() ? &m_data.m_value.boolean : nullptr;
20780 }
20781
20783 constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept
20784 {
20785 return is_boolean() ? &m_data.m_value.boolean : nullptr;
20786 }
20787
20790 {
20791 return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
20792 }
20793
20795 constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept
20796 {
20797 return is_number_integer() ? &m_data.m_value.number_integer : nullptr;
20798 }
20799
20802 {
20803 return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
20804 }
20805
20807 constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept
20808 {
20809 return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;
20810 }
20811
20814 {
20815 return is_number_float() ? &m_data.m_value.number_float : nullptr;
20816 }
20817
20819 constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept
20820 {
20821 return is_number_float() ? &m_data.m_value.number_float : nullptr;
20822 }
20823
20825 binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept
20826 {
20827 return is_binary() ? m_data.m_value.binary : nullptr;
20828 }
20829
20831 constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept
20832 {
20833 return is_binary() ? m_data.m_value.binary : nullptr;
20834 }
20835
20847 template<typename ReferenceType, typename ThisType>
20848 static ReferenceType get_ref_impl(ThisType& obj)
20849 {
20850 // delegate the call to get_ptr<>()
20851 auto* ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();
20852
20853 if (JSON_HEDLEY_LIKELY(ptr != nullptr))
20854 {
20855 return *ptr;
20856 }
20857
20858 JSON_THROW(type_error::create(303, detail::concat("incompatible ReferenceType for get_ref, actual type is ", obj.type_name()), &obj));
20859 }
20860
20861 public:
20865
20868 template<typename PointerType, typename std::enable_if<
20869 std::is_pointer<PointerType>::value, int>::type = 0>
20870 auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
20871 {
20872 // delegate the call to get_impl_ptr<>()
20873 return get_impl_ptr(static_cast<PointerType>(nullptr));
20874 }
20875
20878 template < typename PointerType, typename std::enable_if <
20879 std::is_pointer<PointerType>::value&&
20880 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >
20881 constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))
20882 {
20883 // delegate the call to get_impl_ptr<>() const
20884 return get_impl_ptr(static_cast<PointerType>(nullptr));
20885 }
20886
20887 private:
20926 template < typename ValueType,
20927 detail::enable_if_t <
20930 int > = 0 >
20931 ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept(
20932 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))
20933 {
20934 auto ret = ValueType();
20935 JSONSerializer<ValueType>::from_json(*this, ret);
20936 return ret;
20937 }
20938
20969 template < typename ValueType,
20970 detail::enable_if_t <
20972 int > = 0 >
20973 ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept(
20974 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))
20975 {
20976 return JSONSerializer<ValueType>::from_json(*this);
20977 }
20978
20994 template < typename BasicJsonType,
20995 detail::enable_if_t <
20997 int > = 0 >
20998 BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const
20999 {
21000 return *this;
21001 }
21002
21017 template<typename BasicJsonType,
21018 detail::enable_if_t<
21019 std::is_same<BasicJsonType, basic_json_t>::value,
21020 int> = 0>
21022 {
21023 return *this;
21024 }
21025
21030 template<typename PointerType,
21031 detail::enable_if_t<
21032 std::is_pointer<PointerType>::value,
21033 int> = 0>
21034 constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept
21035 -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())
21036 {
21037 // delegate the call to get_ptr
21038 return get_ptr<PointerType>();
21039 }
21040
21041 public:
21065 template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>
21066#if defined(JSON_HAS_CPP_14)
21067 constexpr
21068#endif
21069 auto get() const noexcept(
21070 noexcept(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {})))
21071 -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))
21072 {
21073 // we cannot static_assert on ValueTypeCV being non-const, because
21074 // there is support for get<const basic_json_t>(), which is why we
21075 // still need the uncvref
21076 static_assert(!std::is_reference<ValueTypeCV>::value,
21077 "get() cannot be used with reference types, you might want to use get_ref()");
21078 return get_impl<ValueType>(detail::priority_tag<4> {});
21079 }
21080
21108 template<typename PointerType, typename std::enable_if<
21109 std::is_pointer<PointerType>::value, int>::type = 0>
21110 auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())
21111 {
21112 // delegate the call to get_ptr
21113 return get_ptr<PointerType>();
21114 }
21115
21118 template < typename ValueType,
21119 detail::enable_if_t <
21122 int > = 0 >
21123 ValueType & get_to(ValueType& v) const noexcept(noexcept(
21124 JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))
21125 {
21126 JSONSerializer<ValueType>::from_json(*this, v);
21127 return v;
21128 }
21129
21130 // specialization to allow calling get_to with a basic_json value
21131 // see https://github.com/nlohmann/json/issues/2175
21132 template<typename ValueType,
21133 detail::enable_if_t <
21135 int> = 0>
21136 ValueType & get_to(ValueType& v) const
21137 {
21138 v = *this;
21139 return v;
21140 }
21141
21142 template <
21143 typename T, std::size_t N,
21144 typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
21145 detail::enable_if_t <
21147 Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
21148 noexcept(noexcept(JSONSerializer<Array>::from_json(
21149 std::declval<const basic_json_t&>(), v)))
21150 {
21151 JSONSerializer<Array>::from_json(*this, v);
21152 return v;
21153 }
21154
21157 template<typename ReferenceType, typename std::enable_if<
21158 std::is_reference<ReferenceType>::value, int>::type = 0>
21159 ReferenceType get_ref()
21160 {
21161 // delegate call to get_ref_impl
21162 return get_ref_impl<ReferenceType>(*this);
21163 }
21164
21167 template < typename ReferenceType, typename std::enable_if <
21168 std::is_reference<ReferenceType>::value&&
21169 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >
21170 ReferenceType get_ref() const
21171 {
21172 // delegate call to get_ref_impl
21173 return get_ref_impl<ReferenceType>(*this);
21174 }
21175
21205 template < typename ValueType, typename std::enable_if <
21213#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
21215#endif
21216#if defined(JSON_HAS_CPP_17) && JSON_HAS_STATIC_RTTI
21218#endif
21220 >::value, int >::type = 0 >
21221 JSON_EXPLICIT operator ValueType() const
21222 {
21223 // delegate the call to get<>() const
21224 return get<ValueType>();
21225 }
21226
21230 {
21231 if (!is_binary())
21232 {
21233 JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
21234 }
21235
21236 return *get_ptr<binary_t*>();
21237 }
21238
21241 const binary_t& get_binary() const
21242 {
21243 if (!is_binary())
21244 {
21245 JSON_THROW(type_error::create(302, detail::concat("type must be binary, but is ", type_name()), this));
21246 }
21247
21248 return *get_ptr<const binary_t*>();
21249 }
21250
21252
21254 // element access //
21256
21260
21264 {
21265 // at only works for arrays
21266 if (JSON_HEDLEY_LIKELY(is_array()))
21267 {
21268 JSON_TRY
21269 {
21270 return set_parent(m_data.m_value.array->at(idx));
21271 }
21272 JSON_CATCH (std::out_of_range&)
21273 {
21274 // create better exception explanation
21275 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
21276 }
21277 }
21278 else
21279 {
21280 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
21281 }
21282 }
21283
21287 {
21288 // at only works for arrays
21289 if (JSON_HEDLEY_LIKELY(is_array()))
21290 {
21291 JSON_TRY
21292 {
21293 return m_data.m_value.array->at(idx);
21294 }
21295 JSON_CATCH (std::out_of_range&)
21296 {
21297 // create better exception explanation
21298 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
21299 }
21300 }
21301 else
21302 {
21303 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
21304 }
21305 }
21306
21309 reference at(const typename object_t::key_type& key)
21310 {
21311 // at only works for objects
21312 if (JSON_HEDLEY_UNLIKELY(!is_object()))
21313 {
21314 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
21315 }
21316
21317 auto it = m_data.m_value.object->find(key);
21318 if (it == m_data.m_value.object->end())
21319 {
21320 JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
21321 }
21322 return set_parent(it->second);
21323 }
21324
21327 template<class KeyType, detail::enable_if_t<
21328 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
21329 reference at(KeyType && key)
21330 {
21331 // at only works for objects
21332 if (JSON_HEDLEY_UNLIKELY(!is_object()))
21333 {
21334 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
21335 }
21336
21337 auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
21338 if (it == m_data.m_value.object->end())
21339 {
21340 JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
21341 }
21342 return set_parent(it->second);
21343 }
21344
21347 const_reference at(const typename object_t::key_type& key) const
21348 {
21349 // at only works for objects
21350 if (JSON_HEDLEY_UNLIKELY(!is_object()))
21351 {
21352 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
21353 }
21354
21355 auto it = m_data.m_value.object->find(key);
21356 if (it == m_data.m_value.object->end())
21357 {
21358 JSON_THROW(out_of_range::create(403, detail::concat("key '", key, "' not found"), this));
21359 }
21360 return it->second;
21361 }
21362
21365 template<class KeyType, detail::enable_if_t<
21366 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
21367 const_reference at(KeyType && key) const
21368 {
21369 // at only works for objects
21370 if (JSON_HEDLEY_UNLIKELY(!is_object()))
21371 {
21372 JSON_THROW(type_error::create(304, detail::concat("cannot use at() with ", type_name()), this));
21373 }
21374
21375 auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
21376 if (it == m_data.m_value.object->end())
21377 {
21378 JSON_THROW(out_of_range::create(403, detail::concat("key '", string_t(std::forward<KeyType>(key)), "' not found"), this));
21379 }
21380 return it->second;
21381 }
21382
21386 {
21387 // implicitly convert null value to an empty array
21388 if (is_null())
21389 {
21390 m_data.m_type = value_t::array;
21391 m_data.m_value.array = create<array_t>();
21392 assert_invariant();
21393 }
21394
21395 // operator[] only works for arrays
21396 if (JSON_HEDLEY_LIKELY(is_array()))
21397 {
21398 // fill up array with null values if given idx is outside range
21399 if (idx >= m_data.m_value.array->size())
21400 {
21401#if JSON_DIAGNOSTICS
21402 // remember array size & capacity before resizing
21403 const auto old_size = m_data.m_value.array->size();
21404 const auto old_capacity = m_data.m_value.array->capacity();
21405#endif
21406 m_data.m_value.array->resize(idx + 1);
21407
21408#if JSON_DIAGNOSTICS
21409 if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))
21410 {
21411 // capacity has changed: update all parents
21412 set_parents();
21413 }
21414 else
21415 {
21416 // set parent for values added above
21417 set_parents(begin() + static_cast<typename iterator::difference_type>(old_size), static_cast<typename iterator::difference_type>(idx + 1 - old_size));
21418 }
21419#endif
21420 assert_invariant();
21421 }
21422
21423 return m_data.m_value.array->operator[](idx);
21424 }
21425
21426 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
21427 }
21428
21432 {
21433 // const operator[] only works for arrays
21434 if (JSON_HEDLEY_LIKELY(is_array()))
21435 {
21436 return m_data.m_value.array->operator[](idx);
21437 }
21438
21439 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a numeric argument with ", type_name()), this));
21440 }
21441
21444 reference operator[](typename object_t::key_type key)
21445 {
21446 // implicitly convert null value to an empty object
21447 if (is_null())
21448 {
21449 m_data.m_type = value_t::object;
21450 m_data.m_value.object = create<object_t>();
21451 assert_invariant();
21452 }
21453
21454 // operator[] only works for objects
21455 if (JSON_HEDLEY_LIKELY(is_object()))
21456 {
21457 auto result = m_data.m_value.object->emplace(std::move(key), nullptr);
21458 return set_parent(result.first->second);
21459 }
21460
21461 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
21462 }
21463
21466 const_reference operator[](const typename object_t::key_type& key) const
21467 {
21468 // const operator[] only works for objects
21469 if (JSON_HEDLEY_LIKELY(is_object()))
21470 {
21471 auto it = m_data.m_value.object->find(key);
21472 JSON_ASSERT(it != m_data.m_value.object->end());
21473 return it->second;
21474 }
21475
21476 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
21477 }
21478
21479 // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC
21480 // (they seemingly cannot be constrained to resolve the ambiguity)
21481 template<typename T>
21482 reference operator[](T* key)
21483 {
21484 return operator[](typename object_t::key_type(key));
21485 }
21486
21487 template<typename T>
21488 const_reference operator[](T* key) const
21489 {
21490 return operator[](typename object_t::key_type(key));
21491 }
21492
21495 template<class KeyType, detail::enable_if_t<
21496 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
21497 reference operator[](KeyType && key)
21498 {
21499 // implicitly convert null value to an empty object
21500 if (is_null())
21501 {
21502 m_data.m_type = value_t::object;
21503 m_data.m_value.object = create<object_t>();
21504 assert_invariant();
21505 }
21506
21507 // operator[] only works for objects
21508 if (JSON_HEDLEY_LIKELY(is_object()))
21509 {
21510 auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr);
21511 return set_parent(result.first->second);
21512 }
21513
21514 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
21515 }
21516
21519 template<class KeyType, detail::enable_if_t<
21520 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >
21521 const_reference operator[](KeyType && key) const
21522 {
21523 // const operator[] only works for objects
21524 if (JSON_HEDLEY_LIKELY(is_object()))
21525 {
21526 auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
21527 JSON_ASSERT(it != m_data.m_value.object->end());
21528 return it->second;
21529 }
21530
21531 JSON_THROW(type_error::create(305, detail::concat("cannot use operator[] with a string argument with ", type_name()), this));
21532 }
21533
21534 private:
21535 template<typename KeyType>
21536 using is_comparable_with_object_key = detail::is_comparable <
21537 object_comparator_t, const typename object_t::key_type&, KeyType >;
21538
21539 template<typename ValueType>
21540 using value_return_type = std::conditional <
21541 detail::is_c_string_uncvref<ValueType>::value,
21542 string_t, typename std::decay<ValueType>::type >;
21543
21544 public:
21547 template < class ValueType, detail::enable_if_t <
21550 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21551 ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const
21552 {
21553 // value only works for objects
21554 if (JSON_HEDLEY_LIKELY(is_object()))
21555 {
21556 // if key is found, return value and given default value otherwise
21557 const auto it = find(key);
21558 if (it != end())
21559 {
21560 return it->template get<ValueType>();
21561 }
21562
21563 return default_value;
21564 }
21565
21566 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
21567 }
21568
21571 template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
21572 detail::enable_if_t <
21575 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21576 ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const
21577 {
21578 // value only works for objects
21579 if (JSON_HEDLEY_LIKELY(is_object()))
21580 {
21581 // if key is found, return value and given default value otherwise
21582 const auto it = find(key);
21583 if (it != end())
21584 {
21585 return it->template get<ReturnType>();
21586 }
21587
21588 return std::forward<ValueType>(default_value);
21589 }
21590
21591 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
21592 }
21593
21596 template < class ValueType, class KeyType, detail::enable_if_t <
21598 && !detail::is_json_pointer<KeyType>::value
21599 && is_comparable_with_object_key<KeyType>::value
21601 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21602 ValueType value(KeyType && key, const ValueType& default_value) const
21603 {
21604 // value only works for objects
21605 if (JSON_HEDLEY_LIKELY(is_object()))
21606 {
21607 // if key is found, return value and given default value otherwise
21608 const auto it = find(std::forward<KeyType>(key));
21609 if (it != end())
21610 {
21611 return it->template get<ValueType>();
21612 }
21613
21614 return default_value;
21615 }
21616
21617 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
21618 }
21619
21622 template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type,
21623 detail::enable_if_t <
21625 && !detail::is_json_pointer<KeyType>::value
21626 && is_comparable_with_object_key<KeyType>::value
21628 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21629 ReturnType value(KeyType && key, ValueType && default_value) const
21630 {
21631 // value only works for objects
21632 if (JSON_HEDLEY_LIKELY(is_object()))
21633 {
21634 // if key is found, return value and given default value otherwise
21635 const auto it = find(std::forward<KeyType>(key));
21636 if (it != end())
21637 {
21638 return it->template get<ReturnType>();
21639 }
21640
21641 return std::forward<ValueType>(default_value);
21642 }
21643
21644 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
21645 }
21646
21649 template < class ValueType, detail::enable_if_t <
21651 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21652 ValueType value(const json_pointer& ptr, const ValueType& default_value) const
21653 {
21654 // value only works for objects
21655 if (JSON_HEDLEY_LIKELY(is_object()))
21656 {
21657 // if pointer resolves a value, return it or use default value
21658 JSON_TRY
21659 {
21660 return ptr.get_checked(this).template get<ValueType>();
21661 }
21662 JSON_INTERNAL_CATCH (out_of_range&)
21663 {
21664 return default_value;
21665 }
21666 }
21667
21668 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
21669 }
21670
21673 template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,
21674 detail::enable_if_t <
21676 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21677 ReturnType value(const json_pointer& ptr, ValueType && default_value) const
21678 {
21679 // value only works for objects
21680 if (JSON_HEDLEY_LIKELY(is_object()))
21681 {
21682 // if pointer resolves a value, return it or use default value
21683 JSON_TRY
21684 {
21685 return ptr.get_checked(this).template get<ReturnType>();
21686 }
21687 JSON_INTERNAL_CATCH (out_of_range&)
21688 {
21689 return std::forward<ValueType>(default_value);
21690 }
21691 }
21692
21693 JSON_THROW(type_error::create(306, detail::concat("cannot use value() with ", type_name()), this));
21694 }
21695
21696 template < class ValueType, class BasicJsonType, detail::enable_if_t <
21699 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21700 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
21701 ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const
21702 {
21703 return value(ptr.convert(), default_value);
21704 }
21705
21706 template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,
21707 detail::enable_if_t <
21710 && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >
21711 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
21712 ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const
21713 {
21714 return value(ptr.convert(), std::forward<ValueType>(default_value));
21715 }
21716
21720 {
21721 return *begin();
21722 }
21723
21727 {
21728 return *cbegin();
21729 }
21730
21734 {
21735 auto tmp = end();
21736 --tmp;
21737 return *tmp;
21738 }
21739
21743 {
21744 auto tmp = cend();
21745 --tmp;
21746 return *tmp;
21747 }
21748
21751 template < class IteratorType, detail::enable_if_t <
21752 std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
21753 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
21754 IteratorType erase(IteratorType pos)
21755 {
21756 // make sure iterator fits the current value
21757 if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))
21758 {
21759 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
21760 }
21761
21762 IteratorType result = end();
21763
21764 switch (m_data.m_type)
21765 {
21766 case value_t::boolean:
21767 case value_t::number_float:
21768 case value_t::number_integer:
21769 case value_t::number_unsigned:
21770 case value_t::string:
21771 case value_t::binary:
21772 {
21773 if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))
21774 {
21775 JSON_THROW(invalid_iterator::create(205, "iterator out of range", this));
21776 }
21777
21778 if (is_string())
21779 {
21780 AllocatorType<string_t> alloc;
21781 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
21782 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
21783 m_data.m_value.string = nullptr;
21784 }
21785 else if (is_binary())
21786 {
21787 AllocatorType<binary_t> alloc;
21788 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
21789 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
21790 m_data.m_value.binary = nullptr;
21791 }
21792
21793 m_data.m_type = value_t::null;
21794 assert_invariant();
21795 break;
21796 }
21797
21798 case value_t::object:
21799 {
21800 result.m_it.object_iterator = m_data.m_value.object->erase(pos.m_it.object_iterator);
21801 break;
21802 }
21803
21804 case value_t::array:
21805 {
21806 result.m_it.array_iterator = m_data.m_value.array->erase(pos.m_it.array_iterator);
21807 break;
21808 }
21809
21810 case value_t::null:
21811 case value_t::discarded:
21812 default:
21813 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
21814 }
21815
21816 return result;
21817 }
21818
21821 template < class IteratorType, detail::enable_if_t <
21822 std::is_same<IteratorType, typename basic_json_t::iterator>::value ||
21823 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >
21824 IteratorType erase(IteratorType first, IteratorType last)
21825 {
21826 // make sure iterator fits the current value
21827 if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))
21828 {
21829 JSON_THROW(invalid_iterator::create(203, "iterators do not fit current value", this));
21830 }
21831
21832 IteratorType result = end();
21833
21834 switch (m_data.m_type)
21835 {
21836 case value_t::boolean:
21837 case value_t::number_float:
21838 case value_t::number_integer:
21839 case value_t::number_unsigned:
21840 case value_t::string:
21841 case value_t::binary:
21842 {
21843 if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()
21844 || !last.m_it.primitive_iterator.is_end()))
21845 {
21846 JSON_THROW(invalid_iterator::create(204, "iterators out of range", this));
21847 }
21848
21849 if (is_string())
21850 {
21851 AllocatorType<string_t> alloc;
21852 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);
21853 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);
21854 m_data.m_value.string = nullptr;
21855 }
21856 else if (is_binary())
21857 {
21858 AllocatorType<binary_t> alloc;
21859 std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);
21860 std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);
21861 m_data.m_value.binary = nullptr;
21862 }
21863
21864 m_data.m_type = value_t::null;
21865 assert_invariant();
21866 break;
21867 }
21868
21869 case value_t::object:
21870 {
21871 result.m_it.object_iterator = m_data.m_value.object->erase(first.m_it.object_iterator,
21872 last.m_it.object_iterator);
21873 break;
21874 }
21875
21876 case value_t::array:
21877 {
21878 result.m_it.array_iterator = m_data.m_value.array->erase(first.m_it.array_iterator,
21879 last.m_it.array_iterator);
21880 break;
21881 }
21882
21883 case value_t::null:
21884 case value_t::discarded:
21885 default:
21886 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
21887 }
21888
21889 return result;
21890 }
21891
21892 private:
21893 template < typename KeyType, detail::enable_if_t <
21894 detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
21895 size_type erase_internal(KeyType && key)
21896 {
21897 // this erase only works for objects
21898 if (JSON_HEDLEY_UNLIKELY(!is_object()))
21899 {
21900 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
21901 }
21902
21903 return m_data.m_value.object->erase(std::forward<KeyType>(key));
21904 }
21905
21906 template < typename KeyType, detail::enable_if_t <
21907 !detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >
21908 size_type erase_internal(KeyType && key)
21909 {
21910 // this erase only works for objects
21911 if (JSON_HEDLEY_UNLIKELY(!is_object()))
21912 {
21913 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
21914 }
21915
21916 const auto it = m_data.m_value.object->find(std::forward<KeyType>(key));
21917 if (it != m_data.m_value.object->end())
21918 {
21919 m_data.m_value.object->erase(it);
21920 return 1;
21921 }
21922 return 0;
21923 }
21924
21925 public:
21926
21929 size_type erase(const typename object_t::key_type& key)
21930 {
21931 // the indirection via erase_internal() is added to avoid making this
21932 // function a template and thus de-rank it during overload resolution
21933 return erase_internal(key);
21934 }
21935
21938 template<class KeyType, detail::enable_if_t<
21939 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
21940 size_type erase(KeyType && key)
21941 {
21942 return erase_internal(std::forward<KeyType>(key));
21943 }
21944
21947 void erase(const size_type idx)
21948 {
21949 // this erase only works for arrays
21950 if (JSON_HEDLEY_LIKELY(is_array()))
21951 {
21952 if (JSON_HEDLEY_UNLIKELY(idx >= size()))
21953 {
21954 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), this));
21955 }
21956
21957 m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx));
21958 }
21959 else
21960 {
21961 JSON_THROW(type_error::create(307, detail::concat("cannot use erase() with ", type_name()), this));
21962 }
21963 }
21964
21966
21968 // lookup //
21970
21973
21976 iterator find(const typename object_t::key_type& key)
21977 {
21978 auto result = end();
21979
21980 if (is_object())
21981 {
21982 result.m_it.object_iterator = m_data.m_value.object->find(key);
21983 }
21984
21985 return result;
21986 }
21987
21990 const_iterator find(const typename object_t::key_type& key) const
21991 {
21992 auto result = cend();
21993
21994 if (is_object())
21995 {
21996 result.m_it.object_iterator = m_data.m_value.object->find(key);
21997 }
21998
21999 return result;
22000 }
22001
22004 template<class KeyType, detail::enable_if_t<
22005 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
22006 iterator find(KeyType && key)
22007 {
22008 auto result = end();
22009
22010 if (is_object())
22011 {
22012 result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
22013 }
22014
22015 return result;
22016 }
22017
22020 template<class KeyType, detail::enable_if_t<
22021 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
22022 const_iterator find(KeyType && key) const
22023 {
22024 auto result = cend();
22025
22026 if (is_object())
22027 {
22028 result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));
22029 }
22030
22031 return result;
22032 }
22033
22036 size_type count(const typename object_t::key_type& key) const
22037 {
22038 // return 0 for all nonobject types
22039 return is_object() ? m_data.m_value.object->count(key) : 0;
22040 }
22041
22044 template<class KeyType, detail::enable_if_t<
22045 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
22046 size_type count(KeyType && key) const
22047 {
22048 // return 0 for all nonobject types
22049 return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0;
22050 }
22051
22054 bool contains(const typename object_t::key_type& key) const
22055 {
22056 return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end();
22057 }
22058
22061 template<class KeyType, detail::enable_if_t<
22062 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>
22063 bool contains(KeyType && key) const
22064 {
22065 return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();
22066 }
22067
22070 bool contains(const json_pointer& ptr) const
22071 {
22072 return ptr.contains(this);
22073 }
22074
22075 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
22076 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
22077 bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const
22078 {
22079 return ptr.contains(this);
22080 }
22081
22083
22085 // iterators //
22087
22090
22093 iterator begin() noexcept
22094 {
22095 iterator result(this);
22096 result.set_begin();
22097 return result;
22098 }
22099
22102 const_iterator begin() const noexcept
22103 {
22104 return cbegin();
22105 }
22106
22109 const_iterator cbegin() const noexcept
22110 {
22111 const_iterator result(this);
22112 result.set_begin();
22113 return result;
22114 }
22115
22118 iterator end() noexcept
22119 {
22120 iterator result(this);
22121 result.set_end();
22122 return result;
22123 }
22124
22127 const_iterator end() const noexcept
22128 {
22129 return cend();
22130 }
22131
22134 const_iterator cend() const noexcept
22135 {
22136 const_iterator result(this);
22137 result.set_end();
22138 return result;
22139 }
22140
22144 {
22145 return reverse_iterator(end());
22146 }
22147
22151 {
22152 return crbegin();
22153 }
22154
22158 {
22159 return reverse_iterator(begin());
22160 }
22161
22165 {
22166 return crend();
22167 }
22168
22172 {
22173 return const_reverse_iterator(cend());
22174 }
22175
22179 {
22180 return const_reverse_iterator(cbegin());
22181 }
22182
22183 public:
22189 JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
22190 static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept
22191 {
22192 return ref.items();
22193 }
22194
22200 JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())
22201 static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept
22202 {
22203 return ref.items();
22204 }
22205
22208 iteration_proxy<iterator> items() noexcept
22209 {
22210 return iteration_proxy<iterator>(*this);
22211 }
22212
22215 iteration_proxy<const_iterator> items() const noexcept
22216 {
22217 return iteration_proxy<const_iterator>(*this);
22218 }
22219
22221
22223 // capacity //
22225
22228
22231 bool empty() const noexcept
22232 {
22233 switch (m_data.m_type)
22234 {
22235 case value_t::null:
22236 {
22237 // null values are empty
22238 return true;
22239 }
22240
22241 case value_t::array:
22242 {
22243 // delegate call to array_t::empty()
22244 return m_data.m_value.array->empty();
22245 }
22246
22247 case value_t::object:
22248 {
22249 // delegate call to object_t::empty()
22250 return m_data.m_value.object->empty();
22251 }
22252
22253 case value_t::string:
22254 case value_t::boolean:
22255 case value_t::number_integer:
22256 case value_t::number_unsigned:
22257 case value_t::number_float:
22258 case value_t::binary:
22259 case value_t::discarded:
22260 default:
22261 {
22262 // all other types are nonempty
22263 return false;
22264 }
22265 }
22266 }
22267
22270 size_type size() const noexcept
22271 {
22272 switch (m_data.m_type)
22273 {
22274 case value_t::null:
22275 {
22276 // null values are empty
22277 return 0;
22278 }
22279
22280 case value_t::array:
22281 {
22282 // delegate call to array_t::size()
22283 return m_data.m_value.array->size();
22284 }
22285
22286 case value_t::object:
22287 {
22288 // delegate call to object_t::size()
22289 return m_data.m_value.object->size();
22290 }
22291
22292 case value_t::string:
22293 case value_t::boolean:
22294 case value_t::number_integer:
22295 case value_t::number_unsigned:
22296 case value_t::number_float:
22297 case value_t::binary:
22298 case value_t::discarded:
22299 default:
22300 {
22301 // all other types have size 1
22302 return 1;
22303 }
22304 }
22305 }
22306
22309 size_type max_size() const noexcept
22310 {
22311 switch (m_data.m_type)
22312 {
22313 case value_t::array:
22314 {
22315 // delegate call to array_t::max_size()
22316 return m_data.m_value.array->max_size();
22317 }
22318
22319 case value_t::object:
22320 {
22321 // delegate call to object_t::max_size()
22322 return m_data.m_value.object->max_size();
22323 }
22324
22325 case value_t::null:
22326 case value_t::string:
22327 case value_t::boolean:
22328 case value_t::number_integer:
22329 case value_t::number_unsigned:
22330 case value_t::number_float:
22331 case value_t::binary:
22332 case value_t::discarded:
22333 default:
22334 {
22335 // all other types have max_size() == size()
22336 return size();
22337 }
22338 }
22339 }
22340
22342
22344 // modifiers //
22346
22349
22352 void clear() noexcept
22353 {
22354 switch (m_data.m_type)
22355 {
22356 case value_t::number_integer:
22357 {
22358 m_data.m_value.number_integer = 0;
22359 break;
22360 }
22361
22362 case value_t::number_unsigned:
22363 {
22364 m_data.m_value.number_unsigned = 0;
22365 break;
22366 }
22367
22368 case value_t::number_float:
22369 {
22370 m_data.m_value.number_float = 0.0;
22371 break;
22372 }
22373
22374 case value_t::boolean:
22375 {
22376 m_data.m_value.boolean = false;
22377 break;
22378 }
22379
22380 case value_t::string:
22381 {
22382 m_data.m_value.string->clear();
22383 break;
22384 }
22385
22386 case value_t::binary:
22387 {
22388 m_data.m_value.binary->clear();
22389 break;
22390 }
22391
22392 case value_t::array:
22393 {
22394 m_data.m_value.array->clear();
22395 break;
22396 }
22397
22398 case value_t::object:
22399 {
22400 m_data.m_value.object->clear();
22401 break;
22402 }
22403
22404 case value_t::null:
22405 case value_t::discarded:
22406 default:
22407 break;
22408 }
22409 }
22410
22414 {
22415 // push_back only works for null objects or arrays
22416 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
22417 {
22418 JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
22419 }
22420
22421 // transform null object into an array
22422 if (is_null())
22423 {
22424 m_data.m_type = value_t::array;
22425 m_data.m_value = value_t::array;
22426 assert_invariant();
22427 }
22428
22429 // add element to array (move semantics)
22430 const auto old_capacity = m_data.m_value.array->capacity();
22431 m_data.m_value.array->push_back(std::move(val));
22432 set_parent(m_data.m_value.array->back(), old_capacity);
22433 // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor
22434 }
22435
22439 {
22440 push_back(std::move(val));
22441 return *this;
22442 }
22443
22446 void push_back(const basic_json& val)
22447 {
22448 // push_back only works for null objects or arrays
22449 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
22450 {
22451 JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
22452 }
22453
22454 // transform null object into an array
22455 if (is_null())
22456 {
22457 m_data.m_type = value_t::array;
22458 m_data.m_value = value_t::array;
22459 assert_invariant();
22460 }
22461
22462 // add element to array
22463 const auto old_capacity = m_data.m_value.array->capacity();
22464 m_data.m_value.array->push_back(val);
22465 set_parent(m_data.m_value.array->back(), old_capacity);
22466 }
22467
22471 {
22472 push_back(val);
22473 return *this;
22474 }
22475
22478 void push_back(const typename object_t::value_type& val)
22479 {
22480 // push_back only works for null objects or objects
22481 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
22482 {
22483 JSON_THROW(type_error::create(308, detail::concat("cannot use push_back() with ", type_name()), this));
22484 }
22485
22486 // transform null object into an object
22487 if (is_null())
22488 {
22489 m_data.m_type = value_t::object;
22490 m_data.m_value = value_t::object;
22491 assert_invariant();
22492 }
22493
22494 // add element to object
22495 auto res = m_data.m_value.object->insert(val);
22496 set_parent(res.first->second);
22497 }
22498
22501 reference operator+=(const typename object_t::value_type& val)
22502 {
22503 push_back(val);
22504 return *this;
22505 }
22506
22510 {
22511 if (is_object() && init.size() == 2 && (*init.begin())->is_string())
22512 {
22513 basic_json&& key = init.begin()->moved_or_copied();
22514 push_back(typename object_t::value_type(
22515 std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));
22516 }
22517 else
22518 {
22519 push_back(basic_json(init));
22520 }
22521 }
22522
22526 {
22527 push_back(init);
22528 return *this;
22529 }
22530
22533 template<class... Args>
22534 reference emplace_back(Args&& ... args)
22535 {
22536 // emplace_back only works for null objects or arrays
22537 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))
22538 {
22539 JSON_THROW(type_error::create(311, detail::concat("cannot use emplace_back() with ", type_name()), this));
22540 }
22541
22542 // transform null object into an array
22543 if (is_null())
22544 {
22545 m_data.m_type = value_t::array;
22546 m_data.m_value = value_t::array;
22547 assert_invariant();
22548 }
22549
22550 // add element to array (perfect forwarding)
22551 const auto old_capacity = m_data.m_value.array->capacity();
22552 m_data.m_value.array->emplace_back(std::forward<Args>(args)...);
22553 return set_parent(m_data.m_value.array->back(), old_capacity);
22554 }
22555
22558 template<class... Args>
22559 std::pair<iterator, bool> emplace(Args&& ... args)
22560 {
22561 // emplace only works for null objects or arrays
22562 if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))
22563 {
22564 JSON_THROW(type_error::create(311, detail::concat("cannot use emplace() with ", type_name()), this));
22565 }
22566
22567 // transform null object into an object
22568 if (is_null())
22569 {
22570 m_data.m_type = value_t::object;
22571 m_data.m_value = value_t::object;
22572 assert_invariant();
22573 }
22574
22575 // add element to array (perfect forwarding)
22576 auto res = m_data.m_value.object->emplace(std::forward<Args>(args)...);
22577 set_parent(res.first->second);
22578
22579 // create result iterator and set iterator to the result of emplace
22580 auto it = begin();
22581 it.m_it.object_iterator = res.first;
22582
22583 // return pair of iterator and boolean
22584 return {it, res.second};
22585 }
22586
22590 template<typename... Args>
22592 {
22593 iterator result(this);
22594 JSON_ASSERT(m_data.m_value.array != nullptr);
22595
22596 auto insert_pos = std::distance(m_data.m_value.array->begin(), pos.m_it.array_iterator);
22597 m_data.m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);
22598 result.m_it.array_iterator = m_data.m_value.array->begin() + insert_pos;
22599
22600 // This could have been written as:
22601 // result.m_it.array_iterator = m_data.m_value.array->insert(pos.m_it.array_iterator, cnt, val);
22602 // but the return value of insert is missing in GCC 4.8, so it is written this way instead.
22603
22604 set_parents();
22605 return result;
22606 }
22607
22611 {
22612 // insert only works for arrays
22613 if (JSON_HEDLEY_LIKELY(is_array()))
22614 {
22615 // check if iterator pos fits to this JSON value
22616 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
22617 {
22618 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
22619 }
22620
22621 // insert to array and return iterator
22622 return insert_iterator(pos, val);
22623 }
22624
22625 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
22626 }
22627
22631 {
22632 return insert(pos, val);
22633 }
22634
22638 {
22639 // insert only works for arrays
22640 if (JSON_HEDLEY_LIKELY(is_array()))
22641 {
22642 // check if iterator pos fits to this JSON value
22643 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
22644 {
22645 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
22646 }
22647
22648 // insert to array and return iterator
22649 return insert_iterator(pos, cnt, val);
22650 }
22651
22652 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
22653 }
22654
22658 {
22659 // insert only works for arrays
22660 if (JSON_HEDLEY_UNLIKELY(!is_array()))
22661 {
22662 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
22663 }
22664
22665 // check if iterator pos fits to this JSON value
22666 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
22667 {
22668 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
22669 }
22670
22671 // check if range iterators belong to the same JSON object
22672 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
22673 {
22674 JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
22675 }
22676
22677 if (JSON_HEDLEY_UNLIKELY(first.m_object == this))
22678 {
22679 JSON_THROW(invalid_iterator::create(211, "passed iterators may not belong to container", this));
22680 }
22681
22682 // insert to array and return iterator
22683 return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);
22684 }
22685
22689 {
22690 // insert only works for arrays
22691 if (JSON_HEDLEY_UNLIKELY(!is_array()))
22692 {
22693 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
22694 }
22695
22696 // check if iterator pos fits to this JSON value
22697 if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))
22698 {
22699 JSON_THROW(invalid_iterator::create(202, "iterator does not fit current value", this));
22700 }
22701
22702 // insert to array and return iterator
22703 return insert_iterator(pos, ilist.begin(), ilist.end());
22704 }
22705
22709 {
22710 // insert only works for objects
22711 if (JSON_HEDLEY_UNLIKELY(!is_object()))
22712 {
22713 JSON_THROW(type_error::create(309, detail::concat("cannot use insert() with ", type_name()), this));
22714 }
22715
22716 // check if range iterators belong to the same JSON object
22717 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
22718 {
22719 JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
22720 }
22721
22722 // passed iterators must belong to objects
22723 if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
22724 {
22725 JSON_THROW(invalid_iterator::create(202, "iterators first and last must point to objects", this));
22726 }
22727
22728 m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);
22729 }
22730
22733 void update(const_reference j, bool merge_objects = false)
22734 {
22735 update(j.begin(), j.end(), merge_objects);
22736 }
22737
22740 void update(const_iterator first, const_iterator last, bool merge_objects = false)
22741 {
22742 // implicitly convert null value to an empty object
22743 if (is_null())
22744 {
22745 m_data.m_type = value_t::object;
22746 m_data.m_value.object = create<object_t>();
22747 assert_invariant();
22748 }
22749
22750 if (JSON_HEDLEY_UNLIKELY(!is_object()))
22751 {
22752 JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", type_name()), this));
22753 }
22754
22755 // check if range iterators belong to the same JSON object
22756 if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))
22757 {
22758 JSON_THROW(invalid_iterator::create(210, "iterators do not fit", this));
22759 }
22760
22761 // passed iterators must belong to objects
22762 if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))
22763 {
22764 JSON_THROW(type_error::create(312, detail::concat("cannot use update() with ", first.m_object->type_name()), first.m_object));
22765 }
22766
22767 for (auto it = first; it != last; ++it)
22768 {
22769 if (merge_objects && it.value().is_object())
22770 {
22771 auto it2 = m_data.m_value.object->find(it.key());
22772 if (it2 != m_data.m_value.object->end())
22773 {
22774 it2->second.update(it.value(), true);
22775 continue;
22776 }
22777 }
22778 m_data.m_value.object->operator[](it.key()) = it.value();
22779#if JSON_DIAGNOSTICS
22780 m_data.m_value.object->operator[](it.key()).m_parent = this;
22781#endif
22782 }
22783 }
22784
22787 void swap(reference other) noexcept (
22788 std::is_nothrow_move_constructible<value_t>::value&&
22789 std::is_nothrow_move_assignable<value_t>::value&&
22790 std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22791 std::is_nothrow_move_assignable<json_value>::value
22792 )
22793 {
22794 std::swap(m_data.m_type, other.m_data.m_type);
22795 std::swap(m_data.m_value, other.m_data.m_value);
22796
22797 set_parents();
22798 other.set_parents();
22799 assert_invariant();
22800 }
22801
22804 friend void swap(reference left, reference right) noexcept (
22805 std::is_nothrow_move_constructible<value_t>::value&&
22806 std::is_nothrow_move_assignable<value_t>::value&&
22807 std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22808 std::is_nothrow_move_assignable<json_value>::value
22809 )
22810 {
22811 left.swap(right);
22812 }
22813
22816 void swap(array_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22817 {
22818 // swap only works for arrays
22819 if (JSON_HEDLEY_LIKELY(is_array()))
22820 {
22821 using std::swap;
22822 swap(*(m_data.m_value.array), other);
22823 }
22824 else
22825 {
22826 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(array_t&) with ", type_name()), this));
22827 }
22828 }
22829
22832 void swap(object_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22833 {
22834 // swap only works for objects
22835 if (JSON_HEDLEY_LIKELY(is_object()))
22836 {
22837 using std::swap;
22838 swap(*(m_data.m_value.object), other);
22839 }
22840 else
22841 {
22842 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(object_t&) with ", type_name()), this));
22843 }
22844 }
22845
22848 void swap(string_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22849 {
22850 // swap only works for strings
22851 if (JSON_HEDLEY_LIKELY(is_string()))
22852 {
22853 using std::swap;
22854 swap(*(m_data.m_value.string), other);
22855 }
22856 else
22857 {
22858 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(string_t&) with ", type_name()), this));
22859 }
22860 }
22861
22864 void swap(binary_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
22865 {
22866 // swap only works for strings
22867 if (JSON_HEDLEY_LIKELY(is_binary()))
22868 {
22869 using std::swap;
22870 swap(*(m_data.m_value.binary), other);
22871 }
22872 else
22873 {
22874 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t&) with ", type_name()), this));
22875 }
22876 }
22877
22880 void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape)
22881 {
22882 // swap only works for strings
22883 if (JSON_HEDLEY_LIKELY(is_binary()))
22884 {
22885 using std::swap;
22886 swap(*(m_data.m_value.binary), other);
22887 }
22888 else
22889 {
22890 JSON_THROW(type_error::create(310, detail::concat("cannot use swap(binary_t::container_type&) with ", type_name()), this));
22891 }
22892 }
22893
22895
22897 // lexicographical comparison operators //
22899
22902
22903 // note parentheses around operands are necessary; see
22904 // https://github.com/nlohmann/json/issues/1530
22905#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result) \
22906 const auto lhs_type = lhs.type(); \
22907 const auto rhs_type = rhs.type(); \
22908 \
22909 if (lhs_type == rhs_type) /* NOLINT(readability/braces) */ \
22910 { \
22911 switch (lhs_type) \
22912 { \
22913 case value_t::array: \
22914 return (*lhs.m_data.m_value.array) op (*rhs.m_data.m_value.array); \
22915 \
22916 case value_t::object: \
22917 return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object); \
22918 \
22919 case value_t::null: \
22920 return (null_result); \
22921 \
22922 case value_t::string: \
22923 return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string); \
22924 \
22925 case value_t::boolean: \
22926 return (lhs.m_data.m_value.boolean) op (rhs.m_data.m_value.boolean); \
22927 \
22928 case value_t::number_integer: \
22929 return (lhs.m_data.m_value.number_integer) op (rhs.m_data.m_value.number_integer); \
22930 \
22931 case value_t::number_unsigned: \
22932 return (lhs.m_data.m_value.number_unsigned) op (rhs.m_data.m_value.number_unsigned); \
22933 \
22934 case value_t::number_float: \
22935 return (lhs.m_data.m_value.number_float) op (rhs.m_data.m_value.number_float); \
22936 \
22937 case value_t::binary: \
22938 return (*lhs.m_data.m_value.binary) op (*rhs.m_data.m_value.binary); \
22939 \
22940 case value_t::discarded: \
22941 default: \
22942 return (unordered_result); \
22943 } \
22944 } \
22945 else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) \
22946 { \
22947 return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float; \
22948 } \
22949 else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) \
22950 { \
22951 return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer); \
22952 } \
22953 else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) \
22954 { \
22955 return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float; \
22956 } \
22957 else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) \
22958 { \
22959 return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned); \
22960 } \
22961 else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \
22962 { \
22963 return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \
22964 } \
22965 else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \
22966 { \
22967 return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned); \
22968 } \
22969 else if(compares_unordered(lhs, rhs))\
22970 {\
22971 return (unordered_result);\
22972 }\
22973 \
22974 return (default_result);
22975
22976 JSON_PRIVATE_UNLESS_TESTED:
22977 // returns true if:
22978 // - any operand is NaN and the other operand is of number type
22979 // - any operand is discarded
22980 // in legacy mode, discarded values are considered ordered if
22981 // an operation is computed as an odd number of inverses of others
22982 static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept
22983 {
22984 if ((lhs.is_number_float() && std::isnan(lhs.m_data.m_value.number_float) && rhs.is_number())
22985 || (rhs.is_number_float() && std::isnan(rhs.m_data.m_value.number_float) && lhs.is_number()))
22986 {
22987 return true;
22988 }
22989#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
22990 return (lhs.is_discarded() || rhs.is_discarded()) && !inverse;
22991#else
22992 static_cast<void>(inverse);
22993 return lhs.is_discarded() || rhs.is_discarded();
22994#endif
22995 }
22996
22997 private:
22998 bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept
22999 {
23000 return compares_unordered(*this, rhs, inverse);
23001 }
23002
23003 public:
23004#if JSON_HAS_THREE_WAY_COMPARISON
23007 bool operator==(const_reference rhs) const noexcept
23008 {
23009#ifdef __GNUC__
23010#pragma GCC diagnostic push
23011#pragma GCC diagnostic ignored "-Wfloat-equal"
23012#endif
23013 const_reference lhs = *this;
23014 JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
23015#ifdef __GNUC__
23016#pragma GCC diagnostic pop
23017#endif
23018 }
23019
23022 template<typename ScalarType>
23023 requires std::is_scalar_v<ScalarType>
23024 bool operator==(ScalarType rhs) const noexcept
23025 {
23026 return *this == basic_json(rhs);
23027 }
23028
23031 bool operator!=(const_reference rhs) const noexcept
23032 {
23033 if (compares_unordered(rhs, true))
23034 {
23035 return false;
23036 }
23037 return !operator==(rhs);
23038 }
23039
23042 std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
23043 {
23044 const_reference lhs = *this;
23045 // default_result is used if we cannot compare values. In that case,
23046 // we compare types.
23047 JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD*
23048 std::partial_ordering::equivalent,
23049 std::partial_ordering::unordered,
23050 lhs_type <=> rhs_type) // *NOPAD*
23051 }
23052
23055 template<typename ScalarType>
23056 requires std::is_scalar_v<ScalarType>
23057 std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD*
23058 {
23059 return *this <=> basic_json(rhs); // *NOPAD*
23060 }
23061
23062#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
23063 // all operators that are computed as an odd number of inverses of others
23064 // need to be overloaded to emulate the legacy comparison behavior
23065
23068 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
23069 bool operator<=(const_reference rhs) const noexcept
23070 {
23071 if (compares_unordered(rhs, true))
23072 {
23073 return false;
23074 }
23075 return !(rhs < *this);
23076 }
23077
23080 template<typename ScalarType>
23081 requires std::is_scalar_v<ScalarType>
23082 bool operator<=(ScalarType rhs) const noexcept
23083 {
23084 return *this <= basic_json(rhs);
23085 }
23086
23089 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
23090 bool operator>=(const_reference rhs) const noexcept
23091 {
23092 if (compares_unordered(rhs, true))
23093 {
23094 return false;
23095 }
23096 return !(*this < rhs);
23097 }
23098
23101 template<typename ScalarType>
23102 requires std::is_scalar_v<ScalarType>
23103 bool operator>=(ScalarType rhs) const noexcept
23104 {
23105 return *this >= basic_json(rhs);
23106 }
23107#endif
23108#else
23111 friend bool operator==(const_reference lhs, const_reference rhs) noexcept
23112 {
23113#ifdef __GNUC__
23114#pragma GCC diagnostic push
23115#pragma GCC diagnostic ignored "-Wfloat-equal"
23116#endif
23117 JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
23118#ifdef __GNUC__
23119#pragma GCC diagnostic pop
23120#endif
23121 }
23122
23125 template<typename ScalarType, typename std::enable_if<
23126 std::is_scalar<ScalarType>::value, int>::type = 0>
23127 friend bool operator==(const_reference lhs, ScalarType rhs) noexcept
23128 {
23129 return lhs == basic_json(rhs);
23130 }
23131
23134 template<typename ScalarType, typename std::enable_if<
23135 std::is_scalar<ScalarType>::value, int>::type = 0>
23136 friend bool operator==(ScalarType lhs, const_reference rhs) noexcept
23137 {
23138 return basic_json(lhs) == rhs;
23139 }
23140
23143 friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
23144 {
23145 if (compares_unordered(lhs, rhs, true))
23146 {
23147 return false;
23148 }
23149 return !(lhs == rhs);
23150 }
23151
23154 template<typename ScalarType, typename std::enable_if<
23155 std::is_scalar<ScalarType>::value, int>::type = 0>
23156 friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept
23157 {
23158 return lhs != basic_json(rhs);
23159 }
23160
23163 template<typename ScalarType, typename std::enable_if<
23164 std::is_scalar<ScalarType>::value, int>::type = 0>
23165 friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept
23166 {
23167 return basic_json(lhs) != rhs;
23168 }
23169
23172 friend bool operator<(const_reference lhs, const_reference rhs) noexcept
23173 {
23174 // default_result is used if we cannot compare values. In that case,
23175 // we compare types. Note we have to call the operator explicitly,
23176 // because MSVC has problems otherwise.
23177 JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type))
23178 }
23179
23182 template<typename ScalarType, typename std::enable_if<
23183 std::is_scalar<ScalarType>::value, int>::type = 0>
23184 friend bool operator<(const_reference lhs, ScalarType rhs) noexcept
23185 {
23186 return lhs < basic_json(rhs);
23187 }
23188
23191 template<typename ScalarType, typename std::enable_if<
23192 std::is_scalar<ScalarType>::value, int>::type = 0>
23193 friend bool operator<(ScalarType lhs, const_reference rhs) noexcept
23194 {
23195 return basic_json(lhs) < rhs;
23196 }
23197
23200 friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
23201 {
23202 if (compares_unordered(lhs, rhs, true))
23203 {
23204 return false;
23205 }
23206 return !(rhs < lhs);
23207 }
23208
23211 template<typename ScalarType, typename std::enable_if<
23212 std::is_scalar<ScalarType>::value, int>::type = 0>
23213 friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept
23214 {
23215 return lhs <= basic_json(rhs);
23216 }
23217
23220 template<typename ScalarType, typename std::enable_if<
23221 std::is_scalar<ScalarType>::value, int>::type = 0>
23222 friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept
23223 {
23224 return basic_json(lhs) <= rhs;
23225 }
23226
23229 friend bool operator>(const_reference lhs, const_reference rhs) noexcept
23230 {
23231 // double inverse
23232 if (compares_unordered(lhs, rhs))
23233 {
23234 return false;
23235 }
23236 return !(lhs <= rhs);
23237 }
23238
23241 template<typename ScalarType, typename std::enable_if<
23242 std::is_scalar<ScalarType>::value, int>::type = 0>
23243 friend bool operator>(const_reference lhs, ScalarType rhs) noexcept
23244 {
23245 return lhs > basic_json(rhs);
23246 }
23247
23250 template<typename ScalarType, typename std::enable_if<
23251 std::is_scalar<ScalarType>::value, int>::type = 0>
23252 friend bool operator>(ScalarType lhs, const_reference rhs) noexcept
23253 {
23254 return basic_json(lhs) > rhs;
23255 }
23256
23259 friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
23260 {
23261 if (compares_unordered(lhs, rhs, true))
23262 {
23263 return false;
23264 }
23265 return !(lhs < rhs);
23266 }
23267
23270 template<typename ScalarType, typename std::enable_if<
23271 std::is_scalar<ScalarType>::value, int>::type = 0>
23272 friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept
23273 {
23274 return lhs >= basic_json(rhs);
23275 }
23276
23279 template<typename ScalarType, typename std::enable_if<
23280 std::is_scalar<ScalarType>::value, int>::type = 0>
23281 friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept
23282 {
23283 return basic_json(lhs) >= rhs;
23284 }
23285#endif
23286
23287#undef JSON_IMPLEMENT_OPERATOR
23288
23290
23292 // serialization //
23294
23297#ifndef JSON_NO_IO
23300 friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
23301 {
23302 // read width member and use it as indentation parameter if nonzero
23303 const bool pretty_print = o.width() > 0;
23304 const auto indentation = pretty_print ? o.width() : 0;
23305
23306 // reset width to 0 for subsequent calls to this stream
23307 o.width(0);
23308
23309 // do the actual serialization
23310 serializer s(detail::output_adapter<char>(o), o.fill());
23311 s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));
23312 return o;
23313 }
23314
23321 JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))
23322 friend std::ostream& operator>>(const basic_json& j, std::ostream& o)
23323 {
23324 return o << j;
23325 }
23326#endif // JSON_NO_IO
23328
23330 // deserialization //
23332
23335
23338 template<typename InputType>
23339 JSON_HEDLEY_WARN_UNUSED_RESULT
23340 static basic_json parse(InputType&& i,
23341 const parser_callback_t cb = nullptr,
23342 const bool allow_exceptions = true,
23343 const bool ignore_comments = false)
23344 {
23345 basic_json result;
23346 parser(detail::input_adapter(std::forward<InputType>(i)), cb, allow_exceptions, ignore_comments).parse(true, result);
23347 return result;
23348 }
23349
23352 template<typename IteratorType>
23353 JSON_HEDLEY_WARN_UNUSED_RESULT
23354 static basic_json parse(IteratorType first,
23355 IteratorType last,
23356 const parser_callback_t cb = nullptr,
23357 const bool allow_exceptions = true,
23358 const bool ignore_comments = false)
23359 {
23360 basic_json result;
23361 parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions, ignore_comments).parse(true, result);
23362 return result;
23363 }
23364
23365 JSON_HEDLEY_WARN_UNUSED_RESULT
23366 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))
23367 static basic_json parse(detail::span_input_adapter&& i,
23368 const parser_callback_t cb = nullptr,
23369 const bool allow_exceptions = true,
23370 const bool ignore_comments = false)
23371 {
23372 basic_json result;
23373 parser(i.get(), cb, allow_exceptions, ignore_comments).parse(true, result);
23374 return result;
23375 }
23376
23379 template<typename InputType>
23380 static bool accept(InputType&& i,
23381 const bool ignore_comments = false)
23382 {
23383 return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);
23384 }
23385
23388 template<typename IteratorType>
23389 static bool accept(IteratorType first, IteratorType last,
23390 const bool ignore_comments = false)
23391 {
23392 return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);
23393 }
23394
23395 JSON_HEDLEY_WARN_UNUSED_RESULT
23396 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))
23397 static bool accept(detail::span_input_adapter&& i,
23398 const bool ignore_comments = false)
23399 {
23400 return parser(i.get(), nullptr, false, ignore_comments).accept(true);
23401 }
23402
23405 template <typename InputType, typename SAX>
23406 JSON_HEDLEY_NON_NULL(2)
23407 static bool sax_parse(InputType&& i, SAX* sax,
23408 input_format_t format = input_format_t::json,
23409 const bool strict = true,
23410 const bool ignore_comments = false)
23411 {
23412 auto ia = detail::input_adapter(std::forward<InputType>(i));
23413 return format == input_format_t::json
23414 ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
23415 : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
23416 }
23417
23420 template<class IteratorType, class SAX>
23421 JSON_HEDLEY_NON_NULL(3)
23422 static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,
23423 input_format_t format = input_format_t::json,
23424 const bool strict = true,
23425 const bool ignore_comments = false)
23426 {
23427 auto ia = detail::input_adapter(std::move(first), std::move(last));
23428 return format == input_format_t::json
23429 ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
23430 : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
23431 }
23432
23438 template <typename SAX>
23439 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))
23440 JSON_HEDLEY_NON_NULL(2)
23441 static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,
23442 input_format_t format = input_format_t::json,
23443 const bool strict = true,
23444 const bool ignore_comments = false)
23445 {
23446 auto ia = i.get();
23447 return format == input_format_t::json
23448 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23449 ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)
23450 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23451 : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);
23452 }
23453#ifndef JSON_NO_IO
23460 JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))
23461 friend std::istream& operator<<(basic_json& j, std::istream& i)
23462 {
23463 return operator>>(i, j);
23464 }
23465
23468 friend std::istream& operator>>(std::istream& i, basic_json& j)
23469 {
23470 parser(detail::input_adapter(i)).parse(false, j);
23471 return i;
23472 }
23473#endif // JSON_NO_IO
23475
23477 // convenience functions //
23479
23482 JSON_HEDLEY_RETURNS_NON_NULL
23483 const char* type_name() const noexcept
23484 {
23485 switch (m_data.m_type)
23486 {
23487 case value_t::null:
23488 return "null";
23489 case value_t::object:
23490 return "object";
23491 case value_t::array:
23492 return "array";
23493 case value_t::string:
23494 return "string";
23495 case value_t::boolean:
23496 return "boolean";
23497 case value_t::binary:
23498 return "binary";
23499 case value_t::discarded:
23500 return "discarded";
23501 case value_t::number_integer:
23502 case value_t::number_unsigned:
23503 case value_t::number_float:
23504 default:
23505 return "number";
23506 }
23507 }
23508
23509 JSON_PRIVATE_UNLESS_TESTED:
23511 // member variables //
23513
23514 struct data
23515 {
23517 value_t m_type = value_t::null;
23518
23520 json_value m_value = {};
23521
23522 data(const value_t v)
23523 : m_type(v), m_value(v)
23524 {
23525 }
23526
23527 data(size_type cnt, const basic_json& val)
23528 : m_type(value_t::array)
23529 {
23530 m_value.array = create<array_t>(cnt, val);
23531 }
23532
23533 data() noexcept = default;
23534 data(data&&) noexcept = default;
23535 data(const data&) noexcept = delete;
23536 data& operator=(data&&) noexcept = delete;
23537 data& operator=(const data&) noexcept = delete;
23538
23539 ~data() noexcept
23540 {
23541 m_value.destroy(m_type);
23542 }
23543 };
23544
23545 data m_data = {};
23546
23547#if JSON_DIAGNOSTICS
23549 basic_json* m_parent = nullptr;
23550#endif
23551
23553 // binary serialization/deserialization //
23555
23558
23559 public:
23562 static std::vector<std::uint8_t> to_cbor(const basic_json& j)
23563 {
23564 std::vector<std::uint8_t> result;
23565 to_cbor(j, result);
23566 return result;
23567 }
23568
23572 {
23573 binary_writer<std::uint8_t>(o).write_cbor(j);
23574 }
23575
23579 {
23580 binary_writer<char>(o).write_cbor(j);
23581 }
23582
23585 static std::vector<std::uint8_t> to_msgpack(const basic_json& j)
23586 {
23587 std::vector<std::uint8_t> result;
23588 to_msgpack(j, result);
23589 return result;
23590 }
23591
23595 {
23596 binary_writer<std::uint8_t>(o).write_msgpack(j);
23597 }
23598
23602 {
23603 binary_writer<char>(o).write_msgpack(j);
23604 }
23605
23608 static std::vector<std::uint8_t> to_ubjson(const basic_json& j,
23609 const bool use_size = false,
23610 const bool use_type = false)
23611 {
23612 std::vector<std::uint8_t> result;
23613 to_ubjson(j, result, use_size, use_type);
23614 return result;
23615 }
23616
23620 const bool use_size = false, const bool use_type = false)
23621 {
23622 binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type);
23623 }
23624
23628 const bool use_size = false, const bool use_type = false)
23629 {
23630 binary_writer<char>(o).write_ubjson(j, use_size, use_type);
23631 }
23632
23635 static std::vector<std::uint8_t> to_bjdata(const basic_json& j,
23636 const bool use_size = false,
23637 const bool use_type = false)
23638 {
23639 std::vector<std::uint8_t> result;
23640 to_bjdata(j, result, use_size, use_type);
23641 return result;
23642 }
23643
23647 const bool use_size = false, const bool use_type = false)
23648 {
23649 binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type, true, true);
23650 }
23651
23655 const bool use_size = false, const bool use_type = false)
23656 {
23657 binary_writer<char>(o).write_ubjson(j, use_size, use_type, true, true);
23658 }
23659
23662 static std::vector<std::uint8_t> to_bson(const basic_json& j)
23663 {
23664 std::vector<std::uint8_t> result;
23665 to_bson(j, result);
23666 return result;
23667 }
23668
23672 {
23673 binary_writer<std::uint8_t>(o).write_bson(j);
23674 }
23675
23679 {
23680 binary_writer<char>(o).write_bson(j);
23681 }
23682
23685 template<typename InputType>
23686 JSON_HEDLEY_WARN_UNUSED_RESULT
23687 static basic_json from_cbor(InputType&& i,
23688 const bool strict = true,
23689 const bool allow_exceptions = true,
23690 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
23691 {
23692 basic_json result;
23693 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23694 auto ia = detail::input_adapter(std::forward<InputType>(i));
23695 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
23696 return res ? result : basic_json(value_t::discarded);
23697 }
23698
23701 template<typename IteratorType>
23702 JSON_HEDLEY_WARN_UNUSED_RESULT
23703 static basic_json from_cbor(IteratorType first, IteratorType last,
23704 const bool strict = true,
23705 const bool allow_exceptions = true,
23706 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
23707 {
23708 basic_json result;
23709 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23710 auto ia = detail::input_adapter(std::move(first), std::move(last));
23711 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
23712 return res ? result : basic_json(value_t::discarded);
23713 }
23714
23715 template<typename T>
23716 JSON_HEDLEY_WARN_UNUSED_RESULT
23717 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
23718 static basic_json from_cbor(const T* ptr, std::size_t len,
23719 const bool strict = true,
23720 const bool allow_exceptions = true,
23721 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
23722 {
23723 return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);
23724 }
23725
23726 JSON_HEDLEY_WARN_UNUSED_RESULT
23727 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))
23728 static basic_json from_cbor(detail::span_input_adapter&& i,
23729 const bool strict = true,
23730 const bool allow_exceptions = true,
23731 const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
23732 {
23733 basic_json result;
23734 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23735 auto ia = i.get();
23736 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23737 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler);
23738 return res ? result : basic_json(value_t::discarded);
23739 }
23740
23743 template<typename InputType>
23744 JSON_HEDLEY_WARN_UNUSED_RESULT
23745 static basic_json from_msgpack(InputType&& i,
23746 const bool strict = true,
23747 const bool allow_exceptions = true)
23748 {
23749 basic_json result;
23750 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23751 auto ia = detail::input_adapter(std::forward<InputType>(i));
23752 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
23753 return res ? result : basic_json(value_t::discarded);
23754 }
23755
23758 template<typename IteratorType>
23759 JSON_HEDLEY_WARN_UNUSED_RESULT
23760 static basic_json from_msgpack(IteratorType first, IteratorType last,
23761 const bool strict = true,
23762 const bool allow_exceptions = true)
23763 {
23764 basic_json result;
23765 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23766 auto ia = detail::input_adapter(std::move(first), std::move(last));
23767 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
23768 return res ? result : basic_json(value_t::discarded);
23769 }
23770
23771 template<typename T>
23772 JSON_HEDLEY_WARN_UNUSED_RESULT
23773 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
23774 static basic_json from_msgpack(const T* ptr, std::size_t len,
23775 const bool strict = true,
23776 const bool allow_exceptions = true)
23777 {
23778 return from_msgpack(ptr, ptr + len, strict, allow_exceptions);
23779 }
23780
23781 JSON_HEDLEY_WARN_UNUSED_RESULT
23782 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))
23783 static basic_json from_msgpack(detail::span_input_adapter&& i,
23784 const bool strict = true,
23785 const bool allow_exceptions = true)
23786 {
23787 basic_json result;
23788 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23789 auto ia = i.get();
23790 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23791 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict);
23792 return res ? result : basic_json(value_t::discarded);
23793 }
23794
23797 template<typename InputType>
23798 JSON_HEDLEY_WARN_UNUSED_RESULT
23799 static basic_json from_ubjson(InputType&& i,
23800 const bool strict = true,
23801 const bool allow_exceptions = true)
23802 {
23803 basic_json result;
23804 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23805 auto ia = detail::input_adapter(std::forward<InputType>(i));
23806 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
23807 return res ? result : basic_json(value_t::discarded);
23808 }
23809
23812 template<typename IteratorType>
23813 JSON_HEDLEY_WARN_UNUSED_RESULT
23814 static basic_json from_ubjson(IteratorType first, IteratorType last,
23815 const bool strict = true,
23816 const bool allow_exceptions = true)
23817 {
23818 basic_json result;
23819 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23820 auto ia = detail::input_adapter(std::move(first), std::move(last));
23821 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
23822 return res ? result : basic_json(value_t::discarded);
23823 }
23824
23825 template<typename T>
23826 JSON_HEDLEY_WARN_UNUSED_RESULT
23827 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
23828 static basic_json from_ubjson(const T* ptr, std::size_t len,
23829 const bool strict = true,
23830 const bool allow_exceptions = true)
23831 {
23832 return from_ubjson(ptr, ptr + len, strict, allow_exceptions);
23833 }
23834
23835 JSON_HEDLEY_WARN_UNUSED_RESULT
23836 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))
23837 static basic_json from_ubjson(detail::span_input_adapter&& i,
23838 const bool strict = true,
23839 const bool allow_exceptions = true)
23840 {
23841 basic_json result;
23842 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23843 auto ia = i.get();
23844 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23845 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict);
23846 return res ? result : basic_json(value_t::discarded);
23847 }
23848
23851 template<typename InputType>
23852 JSON_HEDLEY_WARN_UNUSED_RESULT
23853 static basic_json from_bjdata(InputType&& i,
23854 const bool strict = true,
23855 const bool allow_exceptions = true)
23856 {
23857 basic_json result;
23858 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23859 auto ia = detail::input_adapter(std::forward<InputType>(i));
23860 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
23861 return res ? result : basic_json(value_t::discarded);
23862 }
23863
23866 template<typename IteratorType>
23867 JSON_HEDLEY_WARN_UNUSED_RESULT
23868 static basic_json from_bjdata(IteratorType first, IteratorType last,
23869 const bool strict = true,
23870 const bool allow_exceptions = true)
23871 {
23872 basic_json result;
23873 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23874 auto ia = detail::input_adapter(std::move(first), std::move(last));
23875 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict);
23876 return res ? result : basic_json(value_t::discarded);
23877 }
23878
23881 template<typename InputType>
23882 JSON_HEDLEY_WARN_UNUSED_RESULT
23883 static basic_json from_bson(InputType&& i,
23884 const bool strict = true,
23885 const bool allow_exceptions = true)
23886 {
23887 basic_json result;
23888 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23889 auto ia = detail::input_adapter(std::forward<InputType>(i));
23890 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
23891 return res ? result : basic_json(value_t::discarded);
23892 }
23893
23896 template<typename IteratorType>
23897 JSON_HEDLEY_WARN_UNUSED_RESULT
23898 static basic_json from_bson(IteratorType first, IteratorType last,
23899 const bool strict = true,
23900 const bool allow_exceptions = true)
23901 {
23902 basic_json result;
23903 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23904 auto ia = detail::input_adapter(std::move(first), std::move(last));
23905 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
23906 return res ? result : basic_json(value_t::discarded);
23907 }
23908
23909 template<typename T>
23910 JSON_HEDLEY_WARN_UNUSED_RESULT
23911 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
23912 static basic_json from_bson(const T* ptr, std::size_t len,
23913 const bool strict = true,
23914 const bool allow_exceptions = true)
23915 {
23916 return from_bson(ptr, ptr + len, strict, allow_exceptions);
23917 }
23918
23919 JSON_HEDLEY_WARN_UNUSED_RESULT
23920 JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))
23921 static basic_json from_bson(detail::span_input_adapter&& i,
23922 const bool strict = true,
23923 const bool allow_exceptions = true)
23924 {
23925 basic_json result;
23926 detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
23927 auto ia = i.get();
23928 // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)
23929 const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict);
23930 return res ? result : basic_json(value_t::discarded);
23931 }
23933
23935 // JSON Pointer support //
23937
23940
23944 {
23945 return ptr.get_unchecked(this);
23946 }
23947
23948 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
23949 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
23950 reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)
23951 {
23952 return ptr.get_unchecked(this);
23953 }
23954
23958 {
23959 return ptr.get_unchecked(this);
23960 }
23961
23962 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
23963 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
23964 const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
23965 {
23966 return ptr.get_unchecked(this);
23967 }
23968
23972 {
23973 return ptr.get_checked(this);
23974 }
23975
23976 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
23977 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
23978 reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)
23979 {
23980 return ptr.get_checked(this);
23981 }
23982
23986 {
23987 return ptr.get_checked(this);
23988 }
23989
23990 template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>
23991 JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)
23992 const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const
23993 {
23994 return ptr.get_checked(this);
23995 }
23996
24000 {
24001 basic_json result(value_t::object);
24002 json_pointer::flatten("", *this, result);
24003 return result;
24004 }
24005
24009 {
24010 return json_pointer::unflatten(*this);
24011 }
24012
24014
24016 // JSON Patch functions //
24018
24021
24024 void patch_inplace(const basic_json& json_patch)
24025 {
24026 basic_json& result = *this;
24027 // the valid JSON Patch operations
24028 enum class patch_operations {add, remove, replace, move, copy, test, invalid};
24029
24030 const auto get_op = [](const std::string & op)
24031 {
24032 if (op == "add")
24033 {
24034 return patch_operations::add;
24035 }
24036 if (op == "remove")
24037 {
24038 return patch_operations::remove;
24039 }
24040 if (op == "replace")
24041 {
24042 return patch_operations::replace;
24043 }
24044 if (op == "move")
24045 {
24046 return patch_operations::move;
24047 }
24048 if (op == "copy")
24049 {
24050 return patch_operations::copy;
24051 }
24052 if (op == "test")
24053 {
24054 return patch_operations::test;
24055 }
24056
24057 return patch_operations::invalid;
24058 };
24059
24060 // wrapper for "add" operation; add value at ptr
24061 const auto operation_add = [&result](json_pointer & ptr, basic_json val)
24062 {
24063 // adding to the root of the target document means replacing it
24064 if (ptr.empty())
24065 {
24066 result = val;
24067 return;
24068 }
24069
24070 // make sure the top element of the pointer exists
24071 json_pointer const top_pointer = ptr.top();
24072 if (top_pointer != ptr)
24073 {
24074 result.at(top_pointer);
24075 }
24076
24077 // get reference to parent of JSON pointer ptr
24078 const auto last_path = ptr.back();
24079 ptr.pop_back();
24080 // parent must exist when performing patch add per RFC6902 specs
24081 basic_json& parent = result.at(ptr);
24082
24083 switch (parent.m_data.m_type)
24084 {
24085 case value_t::null:
24086 case value_t::object:
24087 {
24088 // use operator[] to add value
24089 parent[last_path] = val;
24090 break;
24091 }
24092
24093 case value_t::array:
24094 {
24095 if (last_path == "-")
24096 {
24097 // special case: append to back
24098 parent.push_back(val);
24099 }
24100 else
24101 {
24102 const auto idx = json_pointer::template array_index<basic_json_t>(last_path);
24103 if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))
24104 {
24105 // avoid undefined behavior
24106 JSON_THROW(out_of_range::create(401, detail::concat("array index ", std::to_string(idx), " is out of range"), &parent));
24107 }
24108
24109 // default case: insert add offset
24110 parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
24111 }
24112 break;
24113 }
24114
24115 // if there exists a parent it cannot be primitive
24116 case value_t::string: // LCOV_EXCL_LINE
24117 case value_t::boolean: // LCOV_EXCL_LINE
24118 case value_t::number_integer: // LCOV_EXCL_LINE
24119 case value_t::number_unsigned: // LCOV_EXCL_LINE
24120 case value_t::number_float: // LCOV_EXCL_LINE
24121 case value_t::binary: // LCOV_EXCL_LINE
24122 case value_t::discarded: // LCOV_EXCL_LINE
24123 default: // LCOV_EXCL_LINE
24124 JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
24125 }
24126 };
24127
24128 // wrapper for "remove" operation; remove value at ptr
24129 const auto operation_remove = [this, & result](json_pointer & ptr)
24130 {
24131 // get reference to parent of JSON pointer ptr
24132 const auto last_path = ptr.back();
24133 ptr.pop_back();
24134 basic_json& parent = result.at(ptr);
24135
24136 // remove child
24137 if (parent.is_object())
24138 {
24139 // perform range check
24140 auto it = parent.find(last_path);
24141 if (JSON_HEDLEY_LIKELY(it != parent.end()))
24142 {
24143 parent.erase(it);
24144 }
24145 else
24146 {
24147 JSON_THROW(out_of_range::create(403, detail::concat("key '", last_path, "' not found"), this));
24148 }
24149 }
24150 else if (parent.is_array())
24151 {
24152 // note erase performs range check
24153 parent.erase(json_pointer::template array_index<basic_json_t>(last_path));
24154 }
24155 };
24156
24157 // type check: top level value must be an array
24158 if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))
24159 {
24160 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &json_patch));
24161 }
24162
24163 // iterate and apply the operations
24164 for (const auto& val : json_patch)
24165 {
24166 // wrapper to get a value for an operation
24167 const auto get_value = [&val](const std::string & op,
24168 const std::string & member,
24169 bool string_type) -> basic_json &
24170 {
24171 // find value
24172 auto it = val.m_data.m_value.object->find(member);
24173
24174 // context-sensitive error message
24175 const auto error_msg = (op == "op") ? "operation" : detail::concat("operation '", op, '\'');
24176
24177 // check if desired value is present
24178 if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end()))
24179 {
24180 // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
24181 JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have member '", member, "'"), &val));
24182 }
24183
24184 // check if result is of type string
24185 if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))
24186 {
24187 // NOLINTNEXTLINE(performance-inefficient-string-concatenation)
24188 JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, " must have string member '", member, "'"), &val));
24189 }
24190
24191 // no error: return value
24192 return it->second;
24193 };
24194
24195 // type check: every element of the array must be an object
24196 if (JSON_HEDLEY_UNLIKELY(!val.is_object()))
24197 {
24198 JSON_THROW(parse_error::create(104, 0, "JSON patch must be an array of objects", &val));
24199 }
24200
24201 // collect mandatory members
24202 const auto op = get_value("op", "op", true).template get<std::string>();
24203 const auto path = get_value(op, "path", true).template get<std::string>();
24204 json_pointer ptr(path);
24205
24206 switch (get_op(op))
24207 {
24208 case patch_operations::add:
24209 {
24210 operation_add(ptr, get_value("add", "value", false));
24211 break;
24212 }
24213
24214 case patch_operations::remove:
24215 {
24216 operation_remove(ptr);
24217 break;
24218 }
24219
24220 case patch_operations::replace:
24221 {
24222 // the "path" location must exist - use at()
24223 result.at(ptr) = get_value("replace", "value", false);
24224 break;
24225 }
24226
24227 case patch_operations::move:
24228 {
24229 const auto from_path = get_value("move", "from", true).template get<std::string>();
24230 json_pointer from_ptr(from_path);
24231
24232 // the "from" location must exist - use at()
24233 basic_json const v = result.at(from_ptr);
24234
24235 // The move operation is functionally identical to a
24236 // "remove" operation on the "from" location, followed
24237 // immediately by an "add" operation at the target
24238 // location with the value that was just removed.
24239 operation_remove(from_ptr);
24240 operation_add(ptr, v);
24241 break;
24242 }
24243
24244 case patch_operations::copy:
24245 {
24246 const auto from_path = get_value("copy", "from", true).template get<std::string>();
24247 const json_pointer from_ptr(from_path);
24248
24249 // the "from" location must exist - use at()
24250 basic_json const v = result.at(from_ptr);
24251
24252 // The copy is functionally identical to an "add"
24253 // operation at the target location using the value
24254 // specified in the "from" member.
24255 operation_add(ptr, v);
24256 break;
24257 }
24258
24259 case patch_operations::test:
24260 {
24261 bool success = false;
24262 JSON_TRY
24263 {
24264 // check if "value" matches the one at "path"
24265 // the "path" location must exist - use at()
24266 success = (result.at(ptr) == get_value("test", "value", false));
24267 }
24268 JSON_INTERNAL_CATCH (out_of_range&)
24269 {
24270 // ignore out of range errors: success remains false
24271 }
24272
24273 // throw an exception if test fails
24274 if (JSON_HEDLEY_UNLIKELY(!success))
24275 {
24276 JSON_THROW(other_error::create(501, detail::concat("unsuccessful: ", val.dump()), &val));
24277 }
24278
24279 break;
24280 }
24281
24282 case patch_operations::invalid:
24283 default:
24284 {
24285 // op must be "add", "remove", "replace", "move", "copy", or
24286 // "test"
24287 JSON_THROW(parse_error::create(105, 0, detail::concat("operation value '", op, "' is invalid"), &val));
24288 }
24289 }
24290 }
24291 }
24292
24295 basic_json patch(const basic_json& json_patch) const
24296 {
24297 basic_json result = *this;
24298 result.patch_inplace(json_patch);
24299 return result;
24300 }
24301
24304 JSON_HEDLEY_WARN_UNUSED_RESULT
24305 static basic_json diff(const basic_json& source, const basic_json& target,
24306 const std::string& path = "")
24307 {
24308 // the patch
24309 basic_json result(value_t::array);
24310
24311 // if the values are the same, return empty patch
24312 if (source == target)
24313 {
24314 return result;
24315 }
24316
24317 if (source.type() != target.type())
24318 {
24319 // different types: replace value
24320 result.push_back(
24321 {
24322 {"op", "replace"}, {"path", path}, {"value", target}
24323 });
24324 return result;
24325 }
24326
24327 switch (source.type())
24328 {
24329 case value_t::array:
24330 {
24331 // first pass: traverse common elements
24332 std::size_t i = 0;
24333 while (i < source.size() && i < target.size())
24334 {
24335 // recursive call to compare array values at index i
24336 auto temp_diff = diff(source[i], target[i], detail::concat(path, '/', std::to_string(i)));
24337 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
24338 ++i;
24339 }
24340
24341 // We now reached the end of at least one array
24342 // in a second pass, traverse the remaining elements
24343
24344 // remove my remaining elements
24345 const auto end_index = static_cast<difference_type>(result.size());
24346 while (i < source.size())
24347 {
24348 // add operations in reverse order to avoid invalid
24349 // indices
24350 result.insert(result.begin() + end_index, object(
24351 {
24352 {"op", "remove"},
24353 {"path", detail::concat(path, '/', std::to_string(i))}
24354 }));
24355 ++i;
24356 }
24357
24358 // add other remaining elements
24359 while (i < target.size())
24360 {
24361 result.push_back(
24362 {
24363 {"op", "add"},
24364 {"path", detail::concat(path, "/-")},
24365 {"value", target[i]}
24366 });
24367 ++i;
24368 }
24369
24370 break;
24371 }
24372
24373 case value_t::object:
24374 {
24375 // first pass: traverse this object's elements
24376 for (auto it = source.cbegin(); it != source.cend(); ++it)
24377 {
24378 // escape the key name to be used in a JSON patch
24379 const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
24380
24381 if (target.find(it.key()) != target.end())
24382 {
24383 // recursive call to compare object values at key it
24384 auto temp_diff = diff(it.value(), target[it.key()], path_key);
24385 result.insert(result.end(), temp_diff.begin(), temp_diff.end());
24386 }
24387 else
24388 {
24389 // found a key that is not in o -> remove it
24390 result.push_back(object(
24391 {
24392 {"op", "remove"}, {"path", path_key}
24393 }));
24394 }
24395 }
24396
24397 // second pass: traverse other object's elements
24398 for (auto it = target.cbegin(); it != target.cend(); ++it)
24399 {
24400 if (source.find(it.key()) == source.end())
24401 {
24402 // found a key that is not in this -> add it
24403 const auto path_key = detail::concat(path, '/', detail::escape(it.key()));
24404 result.push_back(
24405 {
24406 {"op", "add"}, {"path", path_key},
24407 {"value", it.value()}
24408 });
24409 }
24410 }
24411
24412 break;
24413 }
24414
24415 case value_t::null:
24416 case value_t::string:
24417 case value_t::boolean:
24418 case value_t::number_integer:
24419 case value_t::number_unsigned:
24420 case value_t::number_float:
24421 case value_t::binary:
24422 case value_t::discarded:
24423 default:
24424 {
24425 // both primitive type: replace value
24426 result.push_back(
24427 {
24428 {"op", "replace"}, {"path", path}, {"value", target}
24429 });
24430 break;
24431 }
24432 }
24433
24434 return result;
24435 }
24437
24439 // JSON Merge Patch functions //
24441
24444
24447 void merge_patch(const basic_json& apply_patch)
24448 {
24449 if (apply_patch.is_object())
24450 {
24451 if (!is_object())
24452 {
24453 *this = object();
24454 }
24455 for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)
24456 {
24457 if (it.value().is_null())
24458 {
24459 erase(it.key());
24460 }
24461 else
24462 {
24463 operator[](it.key()).merge_patch(it.value());
24464 }
24465 }
24466 }
24467 else
24468 {
24469 *this = apply_patch;
24470 }
24471 }
24472
24474};
24475
24478NLOHMANN_BASIC_JSON_TPL_DECLARATION
24479std::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)
24480{
24481 return j.dump();
24482}
24483
24484inline namespace literals
24485{
24486inline namespace json_literals
24487{
24488
24491JSON_HEDLEY_NON_NULL(1)
24492#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
24493 inline nlohmann::json operator ""_json(const char* s, std::size_t n)
24494#else
24495 inline nlohmann::json operator "" _json(const char* s, std::size_t n)
24496#endif
24497{
24498 return nlohmann::json::parse(s, s + n);
24499}
24500
24503JSON_HEDLEY_NON_NULL(1)
24504#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
24505 inline nlohmann::json::json_pointer operator ""_json_pointer(const char* s, std::size_t n)
24506#else
24507 inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std::size_t n)
24508#endif
24509{
24510 return nlohmann::json::json_pointer(std::string(s, n));
24511}
24512
24513} // namespace json_literals
24514} // namespace literals
24515NLOHMANN_JSON_NAMESPACE_END
24516
24518// nonmember support //
24520
24521namespace std // NOLINT(cert-dcl58-cpp)
24522{
24523
24526NLOHMANN_BASIC_JSON_TPL_DECLARATION
24527struct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL> // NOLINT(cert-dcl58-cpp)
24528{
24529 std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const
24530 {
24531 return nlohmann::detail::hash(j);
24532 }
24533};
24534
24535// specialization for std::less<value_t>
24536template<>
24537struct less< ::nlohmann::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679
24538{
24543 bool operator()(::nlohmann::detail::value_t lhs,
24544 ::nlohmann::detail::value_t rhs) const noexcept
24545 {
24546#if JSON_HAS_THREE_WAY_COMPARISON
24547 return std::is_lt(lhs <=> rhs); // *NOPAD*
24548#else
24549 return ::nlohmann::detail::operator<(lhs, rhs);
24550#endif
24551 }
24552};
24553
24554// C++20 prohibit function specialization in the std namespace.
24555#ifndef JSON_HAS_CPP_20
24556
24559NLOHMANN_BASIC_JSON_TPL_DECLARATION
24560inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept( // NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp)
24561 is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&& // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)
24562 is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value)
24563{
24564 j1.swap(j2);
24565}
24566
24567#endif
24568
24569} // namespace std
24570
24571#if JSON_USE_GLOBAL_UDLS
24572 #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)
24573 using nlohmann::literals::json_literals::operator ""_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
24574 using nlohmann::literals::json_literals::operator ""_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
24575 #else
24576 using nlohmann::literals::json_literals::operator "" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)
24577 using nlohmann::literals::json_literals::operator "" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)
24578 #endif
24579#endif
24580
24581// #include <nlohmann/detail/macro_unscope.hpp>
24582// __ _____ _____ _____
24583// __| | __| | | | JSON for Modern C++
24584// | | |__ | | | | | | version 3.11.3
24585// |_____|_____|_____|_|___| https://github.com/nlohmann/json
24586//
24587// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
24588// SPDX-License-Identifier: MIT
24589
24590
24591
24592// restore clang diagnostic settings
24593#if defined(__clang__)
24594 #pragma clang diagnostic pop
24595#endif
24596
24597// clean up
24598#undef JSON_ASSERT
24599#undef JSON_INTERNAL_CATCH
24600#undef JSON_THROW
24601#undef JSON_PRIVATE_UNLESS_TESTED
24602#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION
24603#undef NLOHMANN_BASIC_JSON_TPL
24604#undef JSON_EXPLICIT
24605#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL
24606#undef JSON_INLINE_VARIABLE
24607#undef JSON_NO_UNIQUE_ADDRESS
24608#undef JSON_DISABLE_ENUM_SERIALIZATION
24609#undef JSON_USE_GLOBAL_UDLS
24610
24611#ifndef JSON_TEST_KEEP_MACROS
24612 #undef JSON_CATCH
24613 #undef JSON_TRY
24614 #undef JSON_HAS_CPP_11
24615 #undef JSON_HAS_CPP_14
24616 #undef JSON_HAS_CPP_17
24617 #undef JSON_HAS_CPP_20
24618 #undef JSON_HAS_FILESYSTEM
24619 #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
24620 #undef JSON_HAS_THREE_WAY_COMPARISON
24621 #undef JSON_HAS_RANGES
24622 #undef JSON_HAS_STATIC_RTTI
24623 #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
24624#endif
24625
24626// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
24627// __ _____ _____ _____
24628// __| | __| | | | JSON for Modern C++
24629// | | |__ | | | | | | version 3.11.3
24630// |_____|_____|_____|_|___| https://github.com/nlohmann/json
24631//
24632// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
24633// SPDX-License-Identifier: MIT
24634
24635
24636
24637#undef JSON_HEDLEY_ALWAYS_INLINE
24638#undef JSON_HEDLEY_ARM_VERSION
24639#undef JSON_HEDLEY_ARM_VERSION_CHECK
24640#undef JSON_HEDLEY_ARRAY_PARAM
24641#undef JSON_HEDLEY_ASSUME
24642#undef JSON_HEDLEY_BEGIN_C_DECLS
24643#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE
24644#undef JSON_HEDLEY_CLANG_HAS_BUILTIN
24645#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE
24646#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE
24647#undef JSON_HEDLEY_CLANG_HAS_EXTENSION
24648#undef JSON_HEDLEY_CLANG_HAS_FEATURE
24649#undef JSON_HEDLEY_CLANG_HAS_WARNING
24650#undef JSON_HEDLEY_COMPCERT_VERSION
24651#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK
24652#undef JSON_HEDLEY_CONCAT
24653#undef JSON_HEDLEY_CONCAT3
24654#undef JSON_HEDLEY_CONCAT3_EX
24655#undef JSON_HEDLEY_CONCAT_EX
24656#undef JSON_HEDLEY_CONST
24657#undef JSON_HEDLEY_CONSTEXPR
24658#undef JSON_HEDLEY_CONST_CAST
24659#undef JSON_HEDLEY_CPP_CAST
24660#undef JSON_HEDLEY_CRAY_VERSION
24661#undef JSON_HEDLEY_CRAY_VERSION_CHECK
24662#undef JSON_HEDLEY_C_DECL
24663#undef JSON_HEDLEY_DEPRECATED
24664#undef JSON_HEDLEY_DEPRECATED_FOR
24665#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL
24666#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_
24667#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED
24668#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES
24669#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS
24670#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION
24671#undef JSON_HEDLEY_DIAGNOSTIC_POP
24672#undef JSON_HEDLEY_DIAGNOSTIC_PUSH
24673#undef JSON_HEDLEY_DMC_VERSION
24674#undef JSON_HEDLEY_DMC_VERSION_CHECK
24675#undef JSON_HEDLEY_EMPTY_BASES
24676#undef JSON_HEDLEY_EMSCRIPTEN_VERSION
24677#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK
24678#undef JSON_HEDLEY_END_C_DECLS
24679#undef JSON_HEDLEY_FLAGS
24680#undef JSON_HEDLEY_FLAGS_CAST
24681#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE
24682#undef JSON_HEDLEY_GCC_HAS_BUILTIN
24683#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE
24684#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE
24685#undef JSON_HEDLEY_GCC_HAS_EXTENSION
24686#undef JSON_HEDLEY_GCC_HAS_FEATURE
24687#undef JSON_HEDLEY_GCC_HAS_WARNING
24688#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK
24689#undef JSON_HEDLEY_GCC_VERSION
24690#undef JSON_HEDLEY_GCC_VERSION_CHECK
24691#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE
24692#undef JSON_HEDLEY_GNUC_HAS_BUILTIN
24693#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE
24694#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE
24695#undef JSON_HEDLEY_GNUC_HAS_EXTENSION
24696#undef JSON_HEDLEY_GNUC_HAS_FEATURE
24697#undef JSON_HEDLEY_GNUC_HAS_WARNING
24698#undef JSON_HEDLEY_GNUC_VERSION
24699#undef JSON_HEDLEY_GNUC_VERSION_CHECK
24700#undef JSON_HEDLEY_HAS_ATTRIBUTE
24701#undef JSON_HEDLEY_HAS_BUILTIN
24702#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE
24703#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS
24704#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE
24705#undef JSON_HEDLEY_HAS_EXTENSION
24706#undef JSON_HEDLEY_HAS_FEATURE
24707#undef JSON_HEDLEY_HAS_WARNING
24708#undef JSON_HEDLEY_IAR_VERSION
24709#undef JSON_HEDLEY_IAR_VERSION_CHECK
24710#undef JSON_HEDLEY_IBM_VERSION
24711#undef JSON_HEDLEY_IBM_VERSION_CHECK
24712#undef JSON_HEDLEY_IMPORT
24713#undef JSON_HEDLEY_INLINE
24714#undef JSON_HEDLEY_INTEL_CL_VERSION
24715#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK
24716#undef JSON_HEDLEY_INTEL_VERSION
24717#undef JSON_HEDLEY_INTEL_VERSION_CHECK
24718#undef JSON_HEDLEY_IS_CONSTANT
24719#undef JSON_HEDLEY_IS_CONSTEXPR_
24720#undef JSON_HEDLEY_LIKELY
24721#undef JSON_HEDLEY_MALLOC
24722#undef JSON_HEDLEY_MCST_LCC_VERSION
24723#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK
24724#undef JSON_HEDLEY_MESSAGE
24725#undef JSON_HEDLEY_MSVC_VERSION
24726#undef JSON_HEDLEY_MSVC_VERSION_CHECK
24727#undef JSON_HEDLEY_NEVER_INLINE
24728#undef JSON_HEDLEY_NON_NULL
24729#undef JSON_HEDLEY_NO_ESCAPE
24730#undef JSON_HEDLEY_NO_RETURN
24731#undef JSON_HEDLEY_NO_THROW
24732#undef JSON_HEDLEY_NULL
24733#undef JSON_HEDLEY_PELLES_VERSION
24734#undef JSON_HEDLEY_PELLES_VERSION_CHECK
24735#undef JSON_HEDLEY_PGI_VERSION
24736#undef JSON_HEDLEY_PGI_VERSION_CHECK
24737#undef JSON_HEDLEY_PREDICT
24738#undef JSON_HEDLEY_PRINTF_FORMAT
24739#undef JSON_HEDLEY_PRIVATE
24740#undef JSON_HEDLEY_PUBLIC
24741#undef JSON_HEDLEY_PURE
24742#undef JSON_HEDLEY_REINTERPRET_CAST
24743#undef JSON_HEDLEY_REQUIRE
24744#undef JSON_HEDLEY_REQUIRE_CONSTEXPR
24745#undef JSON_HEDLEY_REQUIRE_MSG
24746#undef JSON_HEDLEY_RESTRICT
24747#undef JSON_HEDLEY_RETURNS_NON_NULL
24748#undef JSON_HEDLEY_SENTINEL
24749#undef JSON_HEDLEY_STATIC_ASSERT
24750#undef JSON_HEDLEY_STATIC_CAST
24751#undef JSON_HEDLEY_STRINGIFY
24752#undef JSON_HEDLEY_STRINGIFY_EX
24753#undef JSON_HEDLEY_SUNPRO_VERSION
24754#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK
24755#undef JSON_HEDLEY_TINYC_VERSION
24756#undef JSON_HEDLEY_TINYC_VERSION_CHECK
24757#undef JSON_HEDLEY_TI_ARMCL_VERSION
24758#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK
24759#undef JSON_HEDLEY_TI_CL2000_VERSION
24760#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK
24761#undef JSON_HEDLEY_TI_CL430_VERSION
24762#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK
24763#undef JSON_HEDLEY_TI_CL6X_VERSION
24764#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK
24765#undef JSON_HEDLEY_TI_CL7X_VERSION
24766#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK
24767#undef JSON_HEDLEY_TI_CLPRU_VERSION
24768#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK
24769#undef JSON_HEDLEY_TI_VERSION
24770#undef JSON_HEDLEY_TI_VERSION_CHECK
24771#undef JSON_HEDLEY_UNAVAILABLE
24772#undef JSON_HEDLEY_UNLIKELY
24773#undef JSON_HEDLEY_UNPREDICTABLE
24774#undef JSON_HEDLEY_UNREACHABLE
24775#undef JSON_HEDLEY_UNREACHABLE_RETURN
24776#undef JSON_HEDLEY_VERSION
24777#undef JSON_HEDLEY_VERSION_DECODE_MAJOR
24778#undef JSON_HEDLEY_VERSION_DECODE_MINOR
24779#undef JSON_HEDLEY_VERSION_DECODE_REVISION
24780#undef JSON_HEDLEY_VERSION_ENCODE
24781#undef JSON_HEDLEY_WARNING
24782#undef JSON_HEDLEY_WARN_UNUSED_RESULT
24783#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG
24784#undef JSON_HEDLEY_FALL_THROUGH
24785
24786
24787
24788#endif // INCLUDE_NLOHMANN_JSON_HPP_
24789
24790
24791
24792//
24793// httplib.h
24794//
24795// Copyright (c) 2024 Yuji Hirose. All rights reserved.
24796// MIT License
24797//
24798
24799/* The MIT License (MIT)
24800
24801Copyright (c) 2024 Yuji Hirose (yhirose)
24802
24803Permission is hereby granted, free of charge, to any person obtaining a copy
24804of this software and associated documentation files (the "Software"), to deal
24805in the Software without restriction, including without limitation the rights
24806to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
24807copies of the Software, and to permit persons to whom the Software is
24808furnished to do so, subject to the following conditions:
24809
24810The above copyright notice and this permission notice shall be included in all
24811copies or substantial portions of the Software.
24812
24813THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24814IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24815FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24816AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24817LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24818OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24819SOFTWARE.
24820*/
24821
24822#ifndef CPPHTTPLIB_HTTPLIB_H
24823#define CPPHTTPLIB_HTTPLIB_H
24824
24825#define CPPHTTPLIB_VERSION "0.15.3"
24826
24827/*
24828 * Configuration
24829 */
24830
24831#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND
24832#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5
24833#endif
24834
24835#ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT
24836#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5
24837#endif
24838
24839#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND
24840#define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND 300
24841#endif
24842
24843#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND
24844#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 0
24845#endif
24846
24847#ifndef CPPHTTPLIB_READ_TIMEOUT_SECOND
24848#define CPPHTTPLIB_READ_TIMEOUT_SECOND 5
24849#endif
24850
24851#ifndef CPPHTTPLIB_READ_TIMEOUT_USECOND
24852#define CPPHTTPLIB_READ_TIMEOUT_USECOND 0
24853#endif
24854
24855#ifndef CPPHTTPLIB_WRITE_TIMEOUT_SECOND
24856#define CPPHTTPLIB_WRITE_TIMEOUT_SECOND 5
24857#endif
24858
24859#ifndef CPPHTTPLIB_WRITE_TIMEOUT_USECOND
24860#define CPPHTTPLIB_WRITE_TIMEOUT_USECOND 0
24861#endif
24862
24863#ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND
24864#define CPPHTTPLIB_IDLE_INTERVAL_SECOND 0
24865#endif
24866
24867#ifndef CPPHTTPLIB_IDLE_INTERVAL_USECOND
24868#ifdef _WIN32
24869#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 10000
24870#else
24871#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 0
24872#endif
24873#endif
24874
24875#ifndef CPPHTTPLIB_REQUEST_URI_MAX_LENGTH
24876#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192
24877#endif
24878
24879#ifndef CPPHTTPLIB_HEADER_MAX_LENGTH
24880#define CPPHTTPLIB_HEADER_MAX_LENGTH 8192
24881#endif
24882
24883#ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT
24884#define CPPHTTPLIB_REDIRECT_MAX_COUNT 20
24885#endif
24886
24887#ifndef CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT
24888#define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT 1024
24889#endif
24890
24891#ifndef CPPHTTPLIB_PAYLOAD_MAX_LENGTH
24892#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH ((std::numeric_limits<size_t>::max)())
24893#endif
24894
24895#ifndef CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH
24896#define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 8192
24897#endif
24898
24899#ifndef CPPHTTPLIB_RANGE_MAX_COUNT
24900#define CPPHTTPLIB_RANGE_MAX_COUNT 1024
24901#endif
24902
24903#ifndef CPPHTTPLIB_TCP_NODELAY
24904#define CPPHTTPLIB_TCP_NODELAY false
24905#endif
24906
24907#ifndef CPPHTTPLIB_RECV_BUFSIZ
24908#define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u)
24909#endif
24910
24911#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ
24912#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u)
24913#endif
24914
24915#ifndef CPPHTTPLIB_THREAD_POOL_COUNT
24916#define CPPHTTPLIB_THREAD_POOL_COUNT \
24917 ((std::max)(8u, std::thread::hardware_concurrency() > 0 \
24918 ? std::thread::hardware_concurrency() - 1 \
24919 : 0))
24920#endif
24921
24922#ifndef CPPHTTPLIB_RECV_FLAGS
24923#define CPPHTTPLIB_RECV_FLAGS 0
24924#endif
24925
24926#ifndef CPPHTTPLIB_SEND_FLAGS
24927#define CPPHTTPLIB_SEND_FLAGS 0
24928#endif
24929
24930#ifndef CPPHTTPLIB_LISTEN_BACKLOG
24931#define CPPHTTPLIB_LISTEN_BACKLOG 5
24932#endif
24933
24934/*
24935 * Headers
24936 */
24937
24938#ifdef _WIN32
24939#ifndef _CRT_SECURE_NO_WARNINGS
24940#define _CRT_SECURE_NO_WARNINGS
24941#endif //_CRT_SECURE_NO_WARNINGS
24942
24943#ifndef _CRT_NONSTDC_NO_DEPRECATE
24944#define _CRT_NONSTDC_NO_DEPRECATE
24945#endif //_CRT_NONSTDC_NO_DEPRECATE
24946
24947#if defined(_MSC_VER)
24948#if _MSC_VER < 1900
24949#error Sorry, Visual Studio versions prior to 2015 are not supported
24950#endif
24951
24952#pragma comment(lib, "ws2_32.lib")
24953
24954#ifdef _WIN64
24955using ssize_t = __int64;
24956#else
24957using ssize_t = long;
24958#endif
24959#endif // _MSC_VER
24960
24961#ifndef S_ISREG
24962#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)
24963#endif // S_ISREG
24964
24965#ifndef S_ISDIR
24966#define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR)
24967#endif // S_ISDIR
24968
24969#ifndef NOMINMAX
24970#define NOMINMAX
24971#endif // NOMINMAX
24972
24973#include <io.h>
24974#include <winsock2.h>
24975#include <ws2tcpip.h>
24976
24977#ifndef WSA_FLAG_NO_HANDLE_INHERIT
24978#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
24979#endif
24980
24981using socket_t = SOCKET;
24982#ifdef CPPHTTPLIB_USE_POLL
24983#define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout)
24984#endif
24985
24986#else // not _WIN32
24987
24988#include <arpa/inet.h>
24989#if !defined(_AIX) && !defined(__MVS__)
24990#include <ifaddrs.h>
24991#endif
24992#ifdef __MVS__
24993#include <strings.h>
24994#ifndef NI_MAXHOST
24995#define NI_MAXHOST 1025
24996#endif
24997#endif
24998#include <net/if.h>
24999#include <netdb.h>
25000#include <netinet/in.h>
25001#ifdef __linux__
25002#include <resolv.h>
25003#endif
25004#include <netinet/tcp.h>
25005#ifdef CPPHTTPLIB_USE_POLL
25006#include <poll.h>
25007#endif
25008#include <csignal>
25009#include <pthread.h>
25010#include <sys/mman.h>
25011#include <sys/select.h>
25012#include <sys/socket.h>
25013#include <sys/un.h>
25014#include <unistd.h>
25015
25016using socket_t = int;
25017#ifndef INVALID_SOCKET
25018#define INVALID_SOCKET (-1)
25019#endif
25020#endif //_WIN32
25021
25022#include <algorithm>
25023#include <array>
25024#include <atomic>
25025#include <cassert>
25026#include <cctype>
25027#include <climits>
25028#include <condition_variable>
25029#include <cstring>
25030#include <errno.h>
25031#include <exception>
25032#include <fcntl.h>
25033#include <fstream>
25034#include <functional>
25035#include <iomanip>
25036#include <iostream>
25037#include <list>
25038#include <map>
25039#include <memory>
25040#include <mutex>
25041#include <random>
25042#include <regex>
25043#include <set>
25044#include <sstream>
25045#include <string>
25046#include <sys/stat.h>
25047#include <thread>
25048#include <unordered_map>
25049#include <unordered_set>
25050#include <utility>
25051
25052#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
25053#ifdef _WIN32
25054#include <wincrypt.h>
25055
25056// these are defined in wincrypt.h and it breaks compilation if BoringSSL is
25057// used
25058#undef X509_NAME
25059#undef X509_CERT_PAIR
25060#undef X509_EXTENSIONS
25061#undef PKCS7_SIGNER_INFO
25062
25063#ifdef _MSC_VER
25064#pragma comment(lib, "crypt32.lib")
25065#endif
25066#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
25067#include <TargetConditionals.h>
25068#if TARGET_OS_OSX
25069#include <CoreFoundation/CoreFoundation.h>
25070#include <Security/Security.h>
25071#endif // TARGET_OS_OSX
25072#endif // _WIN32
25073
25074#include <openssl/err.h>
25075#include <openssl/evp.h>
25076#include <openssl/ssl.h>
25077#include <openssl/x509v3.h>
25078
25079#if defined(_WIN32) && defined(OPENSSL_USE_APPLINK)
25080#include <openssl/applink.c>
25081#endif
25082
25083#include <iostream>
25084#include <sstream>
25085
25086#if OPENSSL_VERSION_NUMBER < 0x30000000L
25087#error Sorry, OpenSSL versions prior to 3.0.0 are not supported
25088#endif
25089
25090#endif
25091
25092#ifdef CPPHTTPLIB_ZLIB_SUPPORT
25093#include <zlib.h>
25094#endif
25095
25096#ifdef CPPHTTPLIB_BROTLI_SUPPORT
25097#include <brotli/decode.h>
25098#include <brotli/encode.h>
25099#endif
25100
25101/*
25102 * Declaration
25103 */
25104namespace httplib {
25105
25106namespace detail {
25107
25108/*
25109 * Backport std::make_unique from C++14.
25110 *
25111 * NOTE: This code came up with the following stackoverflow post:
25112 * https://stackoverflow.com/questions/10149840/c-arrays-and-make-unique
25113 *
25114 */
25115
25116template <class T, class... Args>
25117typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
25118make_unique(Args &&...args) {
25119 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
25120}
25121
25122template <class T>
25123typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type
25124make_unique(std::size_t n) {
25125 typedef typename std::remove_extent<T>::type RT;
25126 return std::unique_ptr<T>(new RT[n]);
25127}
25128
25129struct ci {
25130 bool operator()(const std::string &s1, const std::string &s2) const {
25131 return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(),
25132 s2.end(),
25133 [](unsigned char c1, unsigned char c2) {
25134 return ::tolower(c1) < ::tolower(c2);
25135 });
25136 }
25137};
25138
25139// This is based on
25140// "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189".
25141
25143 explicit scope_exit(std::function<void(void)> &&f)
25144 : exit_function(std::move(f)), execute_on_destruction{true} {}
25145
25146 scope_exit(scope_exit &&rhs) noexcept
25147 : exit_function(std::move(rhs.exit_function)),
25148 execute_on_destruction{rhs.execute_on_destruction} {
25149 rhs.release();
25150 }
25151
25152 ~scope_exit() {
25153 if (execute_on_destruction) { this->exit_function(); }
25154 }
25155
25156 void release() { this->execute_on_destruction = false; }
25157
25158private:
25159 scope_exit(const scope_exit &) = delete;
25160 void operator=(const scope_exit &) = delete;
25161 scope_exit &operator=(scope_exit &&) = delete;
25162
25163 std::function<void(void)> exit_function;
25164 bool execute_on_destruction;
25165};
25166
25167} // namespace detail
25168
25169enum StatusCode {
25170 // Information responses
25171 Continue_100 = 100,
25172 SwitchingProtocol_101 = 101,
25173 Processing_102 = 102,
25174 EarlyHints_103 = 103,
25175
25176 // Successful responses
25177 OK_200 = 200,
25178 Created_201 = 201,
25179 Accepted_202 = 202,
25180 NonAuthoritativeInformation_203 = 203,
25181 NoContent_204 = 204,
25182 ResetContent_205 = 205,
25183 PartialContent_206 = 206,
25184 MultiStatus_207 = 207,
25185 AlreadyReported_208 = 208,
25186 IMUsed_226 = 226,
25187
25188 // Redirection messages
25189 MultipleChoices_300 = 300,
25190 MovedPermanently_301 = 301,
25191 Found_302 = 302,
25192 SeeOther_303 = 303,
25193 NotModified_304 = 304,
25194 UseProxy_305 = 305,
25195 unused_306 = 306,
25196 TemporaryRedirect_307 = 307,
25197 PermanentRedirect_308 = 308,
25198
25199 // Client error responses
25200 BadRequest_400 = 400,
25201 Unauthorized_401 = 401,
25202 PaymentRequired_402 = 402,
25203 Forbidden_403 = 403,
25204 NotFound_404 = 404,
25205 MethodNotAllowed_405 = 405,
25206 NotAcceptable_406 = 406,
25207 ProxyAuthenticationRequired_407 = 407,
25208 RequestTimeout_408 = 408,
25209 Conflict_409 = 409,
25210 Gone_410 = 410,
25211 LengthRequired_411 = 411,
25212 PreconditionFailed_412 = 412,
25213 PayloadTooLarge_413 = 413,
25214 UriTooLong_414 = 414,
25215 UnsupportedMediaType_415 = 415,
25216 RangeNotSatisfiable_416 = 416,
25217 ExpectationFailed_417 = 417,
25218 ImATeapot_418 = 418,
25219 MisdirectedRequest_421 = 421,
25220 UnprocessableContent_422 = 422,
25221 Locked_423 = 423,
25222 FailedDependency_424 = 424,
25223 TooEarly_425 = 425,
25224 UpgradeRequired_426 = 426,
25225 PreconditionRequired_428 = 428,
25226 TooManyRequests_429 = 429,
25227 RequestHeaderFieldsTooLarge_431 = 431,
25228 UnavailableForLegalReasons_451 = 451,
25229
25230 // Server error responses
25231 InternalServerError_500 = 500,
25232 NotImplemented_501 = 501,
25233 BadGateway_502 = 502,
25234 ServiceUnavailable_503 = 503,
25235 GatewayTimeout_504 = 504,
25236 HttpVersionNotSupported_505 = 505,
25237 VariantAlsoNegotiates_506 = 506,
25238 InsufficientStorage_507 = 507,
25239 LoopDetected_508 = 508,
25240 NotExtended_510 = 510,
25241 NetworkAuthenticationRequired_511 = 511,
25242};
25243
25244using Headers = std::multimap<std::string, std::string, detail::ci>;
25245
25246using Params = std::multimap<std::string, std::string>;
25247using Match = std::smatch;
25248
25249using Progress = std::function<bool(uint64_t current, uint64_t total)>;
25250
25251struct Response;
25252using ResponseHandler = std::function<bool(const Response &response)>;
25253
25255 std::string name;
25256 std::string content;
25257 std::string filename;
25258 std::string content_type;
25259};
25260using MultipartFormDataItems = std::vector<MultipartFormData>;
25261using MultipartFormDataMap = std::multimap<std::string, MultipartFormData>;
25262
25264public:
25265 DataSink() : os(&sb_), sb_(*this) {}
25266
25267 DataSink(const DataSink &) = delete;
25268 DataSink &operator=(const DataSink &) = delete;
25269 DataSink(DataSink &&) = delete;
25270 DataSink &operator=(DataSink &&) = delete;
25271
25272 std::function<bool(const char *data, size_t data_len)> write;
25273 std::function<bool()> is_writable;
25274 std::function<void()> done;
25275 std::function<void(const Headers &trailer)> done_with_trailer;
25276 std::ostream os;
25277
25278private:
25279 class data_sink_streambuf final : public std::streambuf {
25280 public:
25281 explicit data_sink_streambuf(DataSink &sink) : sink_(sink) {}
25282
25283 protected:
25284 std::streamsize xsputn(const char *s, std::streamsize n) override {
25285 sink_.write(s, static_cast<size_t>(n));
25286 return n;
25287 }
25288
25289 private:
25290 DataSink &sink_;
25291 };
25292
25294};
25295
25296using ContentProvider =
25297 std::function<bool(size_t offset, size_t length, DataSink &sink)>;
25298
25299using ContentProviderWithoutLength =
25300 std::function<bool(size_t offset, DataSink &sink)>;
25301
25302using ContentProviderResourceReleaser = std::function<void(bool success)>;
25303
25305 std::string name;
25306 ContentProviderWithoutLength provider;
25307 std::string filename;
25308 std::string content_type;
25309};
25310using MultipartFormDataProviderItems = std::vector<MultipartFormDataProvider>;
25311
25312using ContentReceiverWithProgress =
25313 std::function<bool(const char *data, size_t data_length, uint64_t offset,
25314 uint64_t total_length)>;
25315
25316using ContentReceiver =
25317 std::function<bool(const char *data, size_t data_length)>;
25318
25319using MultipartContentHeader =
25320 std::function<bool(const MultipartFormData &file)>;
25321
25323public:
25324 using Reader = std::function<bool(ContentReceiver receiver)>;
25325 using MultipartReader = std::function<bool(MultipartContentHeader header,
25326 ContentReceiver receiver)>;
25327
25328 ContentReader(Reader reader, MultipartReader multipart_reader)
25329 : reader_(std::move(reader)),
25330 multipart_reader_(std::move(multipart_reader)) {}
25331
25332 bool operator()(MultipartContentHeader header,
25333 ContentReceiver receiver) const {
25334 return multipart_reader_(std::move(header), std::move(receiver));
25335 }
25336
25337 bool operator()(ContentReceiver receiver) const {
25338 return reader_(std::move(receiver));
25339 }
25340
25341 Reader reader_;
25342 MultipartReader multipart_reader_;
25343};
25344
25345using Range = std::pair<ssize_t, ssize_t>;
25346using Ranges = std::vector<Range>;
25347
25348struct Request {
25349 std::string method;
25350 std::string path;
25351 Headers headers;
25352 std::string body;
25353
25354 std::string remote_addr;
25355 int remote_port = -1;
25356 std::string local_addr;
25357 int local_port = -1;
25358
25359 // for server
25360 std::string version;
25361 std::string target;
25362 Params params;
25363 MultipartFormDataMap files;
25364 Ranges ranges;
25365 Match matches;
25366 std::unordered_map<std::string, std::string> path_params;
25367
25368 // for client
25369 ResponseHandler response_handler;
25370 ContentReceiverWithProgress content_receiver;
25371 Progress progress;
25372#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
25373 const SSL *ssl = nullptr;
25374#endif
25375
25376 bool has_header(const std::string &key) const;
25377 std::string get_header_value(const std::string &key, size_t id = 0) const;
25378 uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const;
25379 size_t get_header_value_count(const std::string &key) const;
25380 void set_header(const std::string &key, const std::string &val);
25381
25382 bool has_param(const std::string &key) const;
25383 std::string get_param_value(const std::string &key, size_t id = 0) const;
25384 size_t get_param_value_count(const std::string &key) const;
25385
25386 bool is_multipart_form_data() const;
25387
25388 bool has_file(const std::string &key) const;
25389 MultipartFormData get_file_value(const std::string &key) const;
25390 std::vector<MultipartFormData> get_file_values(const std::string &key) const;
25391
25392 // private members...
25393 size_t redirect_count_ = CPPHTTPLIB_REDIRECT_MAX_COUNT;
25394 size_t content_length_ = 0;
25395 ContentProvider content_provider_;
25396 bool is_chunked_content_provider_ = false;
25397 size_t authorization_count_ = 0;
25398};
25399
25400struct Response {
25401 std::string version;
25402 int status = -1;
25403 std::string reason;
25404 Headers headers;
25405 std::string body;
25406 std::string location; // Redirect location
25407
25408 bool has_header(const std::string &key) const;
25409 std::string get_header_value(const std::string &key, size_t id = 0) const;
25410 uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const;
25411 size_t get_header_value_count(const std::string &key) const;
25412 void set_header(const std::string &key, const std::string &val);
25413
25414 void set_redirect(const std::string &url, int status = StatusCode::Found_302);
25415 void set_content(const char *s, size_t n, const std::string &content_type);
25416 void set_content(const std::string &s, const std::string &content_type);
25417 void set_content(std::string &&s, const std::string &content_type);
25418
25419 void set_content_provider(
25420 size_t length, const std::string &content_type, ContentProvider provider,
25421 ContentProviderResourceReleaser resource_releaser = nullptr);
25422
25423 void set_content_provider(
25424 const std::string &content_type, ContentProviderWithoutLength provider,
25425 ContentProviderResourceReleaser resource_releaser = nullptr);
25426
25427 void set_chunked_content_provider(
25428 const std::string &content_type, ContentProviderWithoutLength provider,
25429 ContentProviderResourceReleaser resource_releaser = nullptr);
25430
25431 Response() = default;
25432 Response(const Response &) = default;
25433 Response &operator=(const Response &) = default;
25434 Response(Response &&) = default;
25435 Response &operator=(Response &&) = default;
25436 ~Response() {
25437 if (content_provider_resource_releaser_) {
25438 content_provider_resource_releaser_(content_provider_success_);
25439 }
25440 }
25441
25442 // private members...
25443 size_t content_length_ = 0;
25444 ContentProvider content_provider_;
25445 ContentProviderResourceReleaser content_provider_resource_releaser_;
25446 bool is_chunked_content_provider_ = false;
25447 bool content_provider_success_ = false;
25448};
25449
25450class Stream {
25451public:
25452 virtual ~Stream() = default;
25453
25454 virtual bool is_readable() const = 0;
25455 virtual bool is_writable() const = 0;
25456
25457 virtual ssize_t read(char *ptr, size_t size) = 0;
25458 virtual ssize_t write(const char *ptr, size_t size) = 0;
25459 virtual void get_remote_ip_and_port(std::string &ip, int &port) const = 0;
25460 virtual void get_local_ip_and_port(std::string &ip, int &port) const = 0;
25461 virtual socket_t socket() const = 0;
25462
25463 template <typename... Args>
25464 ssize_t write_format(const char *fmt, const Args &...args);
25465 ssize_t write(const char *ptr);
25466 ssize_t write(const std::string &s);
25467};
25468
25470public:
25471 TaskQueue() = default;
25472 virtual ~TaskQueue() = default;
25473
25474 virtual bool enqueue(std::function<void()> fn) = 0;
25475 virtual void shutdown() = 0;
25476
25477 virtual void on_idle() {}
25478};
25479
25480class ThreadPool final : public TaskQueue {
25481public:
25482 explicit ThreadPool(size_t n, size_t mqr = 0)
25483 : shutdown_(false), max_queued_requests_(mqr) {
25484 while (n) {
25485 threads_.emplace_back(worker(*this));
25486 n--;
25487 }
25488 }
25489
25490 ThreadPool(const ThreadPool &) = delete;
25491 ~ThreadPool() override = default;
25492
25493 bool enqueue(std::function<void()> fn) override {
25494 {
25495 std::unique_lock<std::mutex> lock(mutex_);
25496 if (max_queued_requests_ > 0 && jobs_.size() >= max_queued_requests_) {
25497 return false;
25498 }
25499 jobs_.push_back(std::move(fn));
25500 }
25501
25502 cond_.notify_one();
25503 return true;
25504 }
25505
25506 void shutdown() override {
25507 // Stop all worker threads...
25508 {
25509 std::unique_lock<std::mutex> lock(mutex_);
25510 shutdown_ = true;
25511 }
25512
25513 cond_.notify_all();
25514
25515 // Join...
25516 for (auto &t : threads_) {
25517 t.join();
25518 }
25519 }
25520
25521private:
25522 struct worker {
25523 explicit worker(ThreadPool &pool) : pool_(pool) {}
25524
25525 void operator()() {
25526 for (;;) {
25527 std::function<void()> fn;
25528 {
25529 std::unique_lock<std::mutex> lock(pool_.mutex_);
25530
25531 pool_.cond_.wait(
25532 lock, [&] { return !pool_.jobs_.empty() || pool_.shutdown_; });
25533
25534 if (pool_.shutdown_ && pool_.jobs_.empty()) { break; }
25535
25536 fn = pool_.jobs_.front();
25537 pool_.jobs_.pop_front();
25538 }
25539
25540 assert(true == static_cast<bool>(fn));
25541 fn();
25542 }
25543 }
25544
25545 ThreadPool &pool_;
25546 };
25547 friend struct worker;
25548
25549 std::vector<std::thread> threads_;
25550 std::list<std::function<void()>> jobs_;
25551
25552 bool shutdown_;
25553 size_t max_queued_requests_ = 0;
25554
25555 std::condition_variable cond_;
25556 std::mutex mutex_;
25557};
25558
25559using Logger = std::function<void(const Request &, const Response &)>;
25560
25561using SocketOptions = std::function<void(socket_t sock)>;
25562
25563void default_socket_options(socket_t sock);
25564
25565const char *status_message(int status);
25566
25567std::string get_bearer_token_auth(const Request &req);
25568
25569namespace detail {
25570
25572public:
25573 virtual ~MatcherBase() = default;
25574
25575 // Match request path and populate its matches and
25576 virtual bool match(Request &request) const = 0;
25577};
25578
25597class PathParamsMatcher final : public MatcherBase {
25598public:
25599 PathParamsMatcher(const std::string &pattern);
25600
25601 bool match(Request &request) const override;
25602
25603private:
25604 static constexpr char marker = ':';
25605 // Treat segment separators as the end of path parameter capture
25606 // Does not need to handle query parameters as they are parsed before path
25607 // matching
25608 static constexpr char separator = '/';
25609
25610 // Contains static path fragments to match against, excluding the '/' after
25611 // path params
25612 // Fragments are separated by path params
25613 std::vector<std::string> static_fragments_;
25614 // Stores the names of the path parameters to be used as keys in the
25615 // Request::path_params map
25616 std::vector<std::string> param_names_;
25617};
25618
25627class RegexMatcher final : public MatcherBase {
25628public:
25629 RegexMatcher(const std::string &pattern) : regex_(pattern) {}
25630
25631 bool match(Request &request) const override;
25632
25633private:
25634 std::regex regex_;
25635};
25636
25637ssize_t write_headers(Stream &strm, const Headers &headers);
25638
25639} // namespace detail
25640
25641class Server {
25642public:
25643 using Handler = std::function<void(const Request &, Response &)>;
25644
25645 using ExceptionHandler =
25646 std::function<void(const Request &, Response &, std::exception_ptr ep)>;
25647
25648 enum class HandlerResponse {
25649 Handled,
25650 Unhandled,
25651 };
25652 using HandlerWithResponse =
25653 std::function<HandlerResponse(const Request &, Response &)>;
25654
25655 using HandlerWithContentReader = std::function<void(
25656 const Request &, Response &, const ContentReader &content_reader)>;
25657
25658 using Expect100ContinueHandler =
25659 std::function<int(const Request &, Response &)>;
25660
25661 Server();
25662
25663 virtual ~Server();
25664
25665 virtual bool is_valid() const;
25666
25667 Server &Get(const std::string &pattern, Handler handler);
25668 Server &Post(const std::string &pattern, Handler handler);
25669 Server &Post(const std::string &pattern, HandlerWithContentReader handler);
25670 Server &Put(const std::string &pattern, Handler handler);
25671 Server &Put(const std::string &pattern, HandlerWithContentReader handler);
25672 Server &Patch(const std::string &pattern, Handler handler);
25673 Server &Patch(const std::string &pattern, HandlerWithContentReader handler);
25674 Server &Delete(const std::string &pattern, Handler handler);
25675 Server &Delete(const std::string &pattern, HandlerWithContentReader handler);
25676 Server &Options(const std::string &pattern, Handler handler);
25677
25678 bool set_base_dir(const std::string &dir,
25679 const std::string &mount_point = std::string());
25680 bool set_mount_point(const std::string &mount_point, const std::string &dir,
25681 Headers headers = Headers());
25682 bool remove_mount_point(const std::string &mount_point);
25683 Server &set_file_extension_and_mimetype_mapping(const std::string &ext,
25684 const std::string &mime);
25685 Server &set_default_file_mimetype(const std::string &mime);
25686 Server &set_file_request_handler(Handler handler);
25687
25688 template <class ErrorHandlerFunc>
25689 Server &set_error_handler(ErrorHandlerFunc &&handler) {
25690 return set_error_handler_core(
25691 std::forward<ErrorHandlerFunc>(handler),
25692 std::is_convertible<ErrorHandlerFunc, HandlerWithResponse>{});
25693 }
25694
25695 Server &set_exception_handler(ExceptionHandler handler);
25696 Server &set_pre_routing_handler(HandlerWithResponse handler);
25697 Server &set_post_routing_handler(Handler handler);
25698
25699 Server &set_expect_100_continue_handler(Expect100ContinueHandler handler);
25700 Server &set_logger(Logger logger);
25701
25702 Server &set_address_family(int family);
25703 Server &set_tcp_nodelay(bool on);
25704 Server &set_socket_options(SocketOptions socket_options);
25705
25706 Server &set_default_headers(Headers headers);
25707 Server &
25708 set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
25709
25710 Server &set_keep_alive_max_count(size_t count);
25711 Server &set_keep_alive_timeout(time_t sec);
25712
25713 Server &set_read_timeout(time_t sec, time_t usec = 0);
25714 template <class Rep, class Period>
25715 Server &set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
25716
25717 Server &set_write_timeout(time_t sec, time_t usec = 0);
25718 template <class Rep, class Period>
25719 Server &set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
25720
25721 Server &set_idle_interval(time_t sec, time_t usec = 0);
25722 template <class Rep, class Period>
25723 Server &set_idle_interval(const std::chrono::duration<Rep, Period> &duration);
25724
25725 Server &set_payload_max_length(size_t length);
25726
25727 bool bind_to_port(const std::string &host, int port, int socket_flags = 0);
25728 int bind_to_any_port(const std::string &host, int socket_flags = 0);
25729 bool listen_after_bind();
25730
25731 bool listen(const std::string &host, int port, int socket_flags = 0);
25732
25733 bool is_running() const;
25734 void wait_until_ready() const;
25735 void stop();
25736
25737 std::function<TaskQueue *(void)> new_task_queue;
25738
25739protected:
25740 bool process_request(Stream &strm, bool close_connection,
25741 bool &connection_closed,
25742 const std::function<void(Request &)> &setup_request);
25743
25744 std::atomic<socket_t> svr_sock_{INVALID_SOCKET};
25745 size_t keep_alive_max_count_ = CPPHTTPLIB_KEEPALIVE_MAX_COUNT;
25746 time_t keep_alive_timeout_sec_ = CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND;
25747 time_t read_timeout_sec_ = CPPHTTPLIB_READ_TIMEOUT_SECOND;
25748 time_t read_timeout_usec_ = CPPHTTPLIB_READ_TIMEOUT_USECOND;
25749 time_t write_timeout_sec_ = CPPHTTPLIB_WRITE_TIMEOUT_SECOND;
25750 time_t write_timeout_usec_ = CPPHTTPLIB_WRITE_TIMEOUT_USECOND;
25751 time_t idle_interval_sec_ = CPPHTTPLIB_IDLE_INTERVAL_SECOND;
25752 time_t idle_interval_usec_ = CPPHTTPLIB_IDLE_INTERVAL_USECOND;
25753 size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH;
25754
25755private:
25756 using Handlers =
25757 std::vector<std::pair<std::unique_ptr<detail::MatcherBase>, Handler>>;
25758 using HandlersForContentReader =
25759 std::vector<std::pair<std::unique_ptr<detail::MatcherBase>,
25760 HandlerWithContentReader>>;
25761
25762 static std::unique_ptr<detail::MatcherBase>
25763 make_matcher(const std::string &pattern);
25764
25765 Server &set_error_handler_core(HandlerWithResponse handler, std::true_type);
25766 Server &set_error_handler_core(Handler handler, std::false_type);
25767
25768 socket_t create_server_socket(const std::string &host, int port,
25769 int socket_flags,
25770 SocketOptions socket_options) const;
25771 int bind_internal(const std::string &host, int port, int socket_flags);
25772 bool listen_internal();
25773
25774 bool routing(Request &req, Response &res, Stream &strm);
25775 bool handle_file_request(const Request &req, Response &res,
25776 bool head = false);
25777 bool dispatch_request(Request &req, Response &res,
25778 const Handlers &handlers) const;
25779 bool dispatch_request_for_content_reader(
25780 Request &req, Response &res, ContentReader content_reader,
25781 const HandlersForContentReader &handlers) const;
25782
25783 bool parse_request_line(const char *s, Request &req) const;
25784 void apply_ranges(const Request &req, Response &res,
25785 std::string &content_type, std::string &boundary) const;
25786 bool write_response(Stream &strm, bool close_connection, Request &req,
25787 Response &res);
25788 bool write_response_with_content(Stream &strm, bool close_connection,
25789 const Request &req, Response &res);
25790 bool write_response_core(Stream &strm, bool close_connection,
25791 const Request &req, Response &res,
25792 bool need_apply_ranges);
25793 bool write_content_with_provider(Stream &strm, const Request &req,
25794 Response &res, const std::string &boundary,
25795 const std::string &content_type);
25796 bool read_content(Stream &strm, Request &req, Response &res);
25797 bool
25798 read_content_with_content_receiver(Stream &strm, Request &req, Response &res,
25799 ContentReceiver receiver,
25800 MultipartContentHeader multipart_header,
25801 ContentReceiver multipart_receiver);
25802 bool read_content_core(Stream &strm, Request &req, Response &res,
25803 ContentReceiver receiver,
25804 MultipartContentHeader multipart_header,
25805 ContentReceiver multipart_receiver) const;
25806
25807 virtual bool process_and_close_socket(socket_t sock);
25808
25809 std::atomic<bool> is_running_{false};
25810 std::atomic<bool> done_{false};
25811
25813 std::string mount_point;
25814 std::string base_dir;
25815 Headers headers;
25816 };
25817 std::vector<MountPointEntry> base_dirs_;
25818 std::map<std::string, std::string> file_extension_and_mimetype_map_;
25819 std::string default_file_mimetype_ = "application/octet-stream";
25820 Handler file_request_handler_;
25821
25822 Handlers get_handlers_;
25823 Handlers post_handlers_;
25824 HandlersForContentReader post_handlers_for_content_reader_;
25825 Handlers put_handlers_;
25826 HandlersForContentReader put_handlers_for_content_reader_;
25827 Handlers patch_handlers_;
25828 HandlersForContentReader patch_handlers_for_content_reader_;
25829 Handlers delete_handlers_;
25830 HandlersForContentReader delete_handlers_for_content_reader_;
25831 Handlers options_handlers_;
25832
25833 HandlerWithResponse error_handler_;
25834 ExceptionHandler exception_handler_;
25835 HandlerWithResponse pre_routing_handler_;
25836 Handler post_routing_handler_;
25837 Expect100ContinueHandler expect_100_continue_handler_;
25838
25839 Logger logger_;
25840
25841 int address_family_ = AF_UNSPEC;
25842 bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
25843 SocketOptions socket_options_ = default_socket_options;
25844
25845 Headers default_headers_;
25846 std::function<ssize_t(Stream &, Headers &)> header_writer_ =
25847 detail::write_headers;
25848};
25849
25850enum class Error {
25851 Success = 0,
25852 Unknown,
25853 Connection,
25854 BindIPAddress,
25855 Read,
25856 Write,
25857 ExceedRedirectCount,
25858 Canceled,
25859 SSLConnection,
25860 SSLLoadingCerts,
25861 SSLServerVerification,
25862 UnsupportedMultipartBoundaryChars,
25863 Compression,
25864 ConnectionTimeout,
25865 ProxyConnection,
25866
25867 // For internal use only
25868 SSLPeerCouldBeClosed_,
25869};
25870
25871std::string to_string(Error error);
25872
25873std::ostream &operator<<(std::ostream &os, const Error &obj);
25874
25875class Result {
25876public:
25877 Result() = default;
25878 Result(std::unique_ptr<Response> &&res, Error err,
25879 Headers &&request_headers = Headers{})
25880 : res_(std::move(res)), err_(err),
25881 request_headers_(std::move(request_headers)) {}
25882 // Response
25883 operator bool() const { return res_ != nullptr; }
25884 bool operator==(std::nullptr_t) const { return res_ == nullptr; }
25885 bool operator!=(std::nullptr_t) const { return res_ != nullptr; }
25886 const Response &value() const { return *res_; }
25887 Response &value() { return *res_; }
25888 const Response &operator*() const { return *res_; }
25889 Response &operator*() { return *res_; }
25890 const Response *operator->() const { return res_.get(); }
25891 Response *operator->() { return res_.get(); }
25892
25893 // Error
25894 Error error() const { return err_; }
25895
25896 // Request Headers
25897 bool has_request_header(const std::string &key) const;
25898 std::string get_request_header_value(const std::string &key,
25899 size_t id = 0) const;
25900 uint64_t get_request_header_value_u64(const std::string &key,
25901 size_t id = 0) const;
25902 size_t get_request_header_value_count(const std::string &key) const;
25903
25904private:
25905 std::unique_ptr<Response> res_;
25906 Error err_ = Error::Unknown;
25907 Headers request_headers_;
25908};
25909
25911public:
25912 explicit ClientImpl(const std::string &host);
25913
25914 explicit ClientImpl(const std::string &host, int port);
25915
25916 explicit ClientImpl(const std::string &host, int port,
25917 const std::string &client_cert_path,
25918 const std::string &client_key_path);
25919
25920 virtual ~ClientImpl();
25921
25922 virtual bool is_valid() const;
25923
25924 Result Get(const std::string &path);
25925 Result Get(const std::string &path, const Headers &headers);
25926 Result Get(const std::string &path, Progress progress);
25927 Result Get(const std::string &path, const Headers &headers,
25928 Progress progress);
25929 Result Get(const std::string &path, ContentReceiver content_receiver);
25930 Result Get(const std::string &path, const Headers &headers,
25931 ContentReceiver content_receiver);
25932 Result Get(const std::string &path, ContentReceiver content_receiver,
25933 Progress progress);
25934 Result Get(const std::string &path, const Headers &headers,
25935 ContentReceiver content_receiver, Progress progress);
25936 Result Get(const std::string &path, ResponseHandler response_handler,
25937 ContentReceiver content_receiver);
25938 Result Get(const std::string &path, const Headers &headers,
25939 ResponseHandler response_handler,
25940 ContentReceiver content_receiver);
25941 Result Get(const std::string &path, ResponseHandler response_handler,
25942 ContentReceiver content_receiver, Progress progress);
25943 Result Get(const std::string &path, const Headers &headers,
25944 ResponseHandler response_handler, ContentReceiver content_receiver,
25945 Progress progress);
25946
25947 Result Get(const std::string &path, const Params &params,
25948 const Headers &headers, Progress progress = nullptr);
25949 Result Get(const std::string &path, const Params &params,
25950 const Headers &headers, ContentReceiver content_receiver,
25951 Progress progress = nullptr);
25952 Result Get(const std::string &path, const Params &params,
25953 const Headers &headers, ResponseHandler response_handler,
25954 ContentReceiver content_receiver, Progress progress = nullptr);
25955
25956 Result Head(const std::string &path);
25957 Result Head(const std::string &path, const Headers &headers);
25958
25959 Result Post(const std::string &path);
25960 Result Post(const std::string &path, const Headers &headers);
25961 Result Post(const std::string &path, const char *body, size_t content_length,
25962 const std::string &content_type);
25963 Result Post(const std::string &path, const Headers &headers, const char *body,
25964 size_t content_length, const std::string &content_type);
25965 Result Post(const std::string &path, const Headers &headers, const char *body,
25966 size_t content_length, const std::string &content_type,
25967 Progress progress);
25968
25969 Result Post(const std::string &path, const std::string &body,
25970 const std::string &content_type);
25971
25972 Result Post(const std::string &path, const std::string &body,
25973 const std::string &content_type, ContentReceiver content_receiver);
25974
25975 Result Post(const std::string &path, const Headers &headers,
25976 const std::string &body,
25977 const std::string &content_type,
25978 ContentReceiver content_receiver);
25979
25980 Result Post(const std::string &path, const std::string &body,
25981 const std::string &content_type, Progress progress);
25982 Result Post(const std::string &path, const Headers &headers,
25983 const std::string &body, const std::string &content_type);
25984 Result Post(const std::string &path, const Headers &headers,
25985 const std::string &body, const std::string &content_type,
25986 Progress progress);
25987 Result Post(const std::string &path, size_t content_length,
25988 ContentProvider content_provider,
25989 const std::string &content_type);
25990 Result Post(const std::string &path,
25991 ContentProviderWithoutLength content_provider,
25992 const std::string &content_type);
25993 Result Post(const std::string &path, const Headers &headers,
25994 size_t content_length, ContentProvider content_provider,
25995 const std::string &content_type);
25996 Result Post(const std::string &path, const Headers &headers,
25997 ContentProviderWithoutLength content_provider,
25998 const std::string &content_type);
25999 Result Post(const std::string &path, const Params &params);
26000 Result Post(const std::string &path, const Headers &headers,
26001 const Params &params);
26002 Result Post(const std::string &path, const Headers &headers,
26003 const Params &params, Progress progress);
26004 Result Post(const std::string &path, const MultipartFormDataItems &items);
26005 Result Post(const std::string &path, const Headers &headers,
26006 const MultipartFormDataItems &items);
26007 Result Post(const std::string &path, const Headers &headers,
26008 const MultipartFormDataItems &items, const std::string &boundary);
26009 Result Post(const std::string &path, const Headers &headers,
26010 const MultipartFormDataItems &items,
26011 const MultipartFormDataProviderItems &provider_items);
26012
26013 Result Put(const std::string &path);
26014 Result Put(const std::string &path, const char *body, size_t content_length,
26015 const std::string &content_type);
26016 Result Put(const std::string &path, const Headers &headers, const char *body,
26017 size_t content_length, const std::string &content_type);
26018 Result Put(const std::string &path, const Headers &headers, const char *body,
26019 size_t content_length, const std::string &content_type,
26020 Progress progress);
26021 Result Put(const std::string &path, const std::string &body,
26022 const std::string &content_type);
26023 Result Put(const std::string &path, const std::string &body,
26024 const std::string &content_type, Progress progress);
26025 Result Put(const std::string &path, const Headers &headers,
26026 const std::string &body, const std::string &content_type);
26027 Result Put(const std::string &path, const Headers &headers,
26028 const std::string &body, const std::string &content_type,
26029 Progress progress);
26030 Result Put(const std::string &path, size_t content_length,
26031 ContentProvider content_provider, const std::string &content_type);
26032 Result Put(const std::string &path,
26033 ContentProviderWithoutLength content_provider,
26034 const std::string &content_type);
26035 Result Put(const std::string &path, const Headers &headers,
26036 size_t content_length, ContentProvider content_provider,
26037 const std::string &content_type);
26038 Result Put(const std::string &path, const Headers &headers,
26039 ContentProviderWithoutLength content_provider,
26040 const std::string &content_type);
26041 Result Put(const std::string &path, const Params &params);
26042 Result Put(const std::string &path, const Headers &headers,
26043 const Params &params);
26044 Result Put(const std::string &path, const Headers &headers,
26045 const Params &params, Progress progress);
26046 Result Put(const std::string &path, const MultipartFormDataItems &items);
26047 Result Put(const std::string &path, const Headers &headers,
26048 const MultipartFormDataItems &items);
26049 Result Put(const std::string &path, const Headers &headers,
26050 const MultipartFormDataItems &items, const std::string &boundary);
26051 Result Put(const std::string &path, const Headers &headers,
26052 const MultipartFormDataItems &items,
26053 const MultipartFormDataProviderItems &provider_items);
26054
26055 Result Patch(const std::string &path);
26056 Result Patch(const std::string &path, const char *body, size_t content_length,
26057 const std::string &content_type);
26058 Result Patch(const std::string &path, const char *body, size_t content_length,
26059 const std::string &content_type, Progress progress);
26060 Result Patch(const std::string &path, const Headers &headers,
26061 const char *body, size_t content_length,
26062 const std::string &content_type);
26063 Result Patch(const std::string &path, const Headers &headers,
26064 const char *body, size_t content_length,
26065 const std::string &content_type, Progress progress);
26066 Result Patch(const std::string &path, const std::string &body,
26067 const std::string &content_type);
26068 Result Patch(const std::string &path, const std::string &body,
26069 const std::string &content_type, Progress progress);
26070 Result Patch(const std::string &path, const Headers &headers,
26071 const std::string &body, const std::string &content_type);
26072 Result Patch(const std::string &path, const Headers &headers,
26073 const std::string &body, const std::string &content_type,
26074 Progress progress);
26075 Result Patch(const std::string &path, size_t content_length,
26076 ContentProvider content_provider,
26077 const std::string &content_type);
26078 Result Patch(const std::string &path,
26079 ContentProviderWithoutLength content_provider,
26080 const std::string &content_type);
26081 Result Patch(const std::string &path, const Headers &headers,
26082 size_t content_length, ContentProvider content_provider,
26083 const std::string &content_type);
26084 Result Patch(const std::string &path, const Headers &headers,
26085 ContentProviderWithoutLength content_provider,
26086 const std::string &content_type);
26087
26088 Result Delete(const std::string &path);
26089 Result Delete(const std::string &path, const Headers &headers);
26090 Result Delete(const std::string &path, const char *body,
26091 size_t content_length, const std::string &content_type);
26092 Result Delete(const std::string &path, const char *body,
26093 size_t content_length, const std::string &content_type,
26094 Progress progress);
26095 Result Delete(const std::string &path, const Headers &headers,
26096 const char *body, size_t content_length,
26097 const std::string &content_type);
26098 Result Delete(const std::string &path, const Headers &headers,
26099 const char *body, size_t content_length,
26100 const std::string &content_type, Progress progress);
26101 Result Delete(const std::string &path, const std::string &body,
26102 const std::string &content_type);
26103 Result Delete(const std::string &path, const std::string &body,
26104 const std::string &content_type, Progress progress);
26105 Result Delete(const std::string &path, const Headers &headers,
26106 const std::string &body, const std::string &content_type);
26107 Result Delete(const std::string &path, const Headers &headers,
26108 const std::string &body, const std::string &content_type,
26109 Progress progress);
26110
26111 Result Options(const std::string &path);
26112 Result Options(const std::string &path, const Headers &headers);
26113
26114 bool send(Request &req, Response &res, Error &error);
26115 Result send(const Request &req);
26116
26117 void stop();
26118
26119 std::string host() const;
26120 int port() const;
26121
26122 size_t is_socket_open() const;
26123 socket_t socket() const;
26124
26125 void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
26126
26127 void set_default_headers(Headers headers);
26128
26129 void
26130 set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
26131
26132 void set_address_family(int family);
26133 void set_tcp_nodelay(bool on);
26134 void set_socket_options(SocketOptions socket_options);
26135
26136 void set_connection_timeout(time_t sec, time_t usec = 0);
26137 template <class Rep, class Period>
26138 void
26139 set_connection_timeout(const std::chrono::duration<Rep, Period> &duration);
26140
26141 void set_read_timeout(time_t sec, time_t usec = 0);
26142 template <class Rep, class Period>
26143 void set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
26144
26145 void set_write_timeout(time_t sec, time_t usec = 0);
26146 template <class Rep, class Period>
26147 void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
26148
26149 void set_basic_auth(const std::string &username, const std::string &password);
26150 void set_bearer_token_auth(const std::string &token);
26151#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26152 void set_digest_auth(const std::string &username,
26153 const std::string &password);
26154#endif
26155
26156 void set_keep_alive(bool on);
26157 void set_follow_location(bool on);
26158
26159 void set_url_encode(bool on);
26160
26161 void set_compress(bool on);
26162
26163 void set_decompress(bool on);
26164
26165 void set_interface(const std::string &intf);
26166
26167 void set_proxy(const std::string &host, int port);
26168 void set_proxy_basic_auth(const std::string &username,
26169 const std::string &password);
26170 void set_proxy_bearer_token_auth(const std::string &token);
26171#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26172 void set_proxy_digest_auth(const std::string &username,
26173 const std::string &password);
26174#endif
26175
26176#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26177 void set_ca_cert_path(const std::string &ca_cert_file_path,
26178 const std::string &ca_cert_dir_path = std::string());
26179 void set_ca_cert_store(X509_STORE *ca_cert_store);
26180 X509_STORE *create_ca_cert_store(const char *ca_cert, std::size_t size) const;
26181#endif
26182
26183#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26184 void enable_server_certificate_verification(bool enabled);
26185#endif
26186
26187 void set_logger(Logger logger);
26188
26189protected:
26190 struct Socket {
26191 socket_t sock = INVALID_SOCKET;
26192#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26193 SSL *ssl = nullptr;
26194#endif
26195
26196 bool is_open() const { return sock != INVALID_SOCKET; }
26197 };
26198
26199 virtual bool create_and_connect_socket(Socket &socket, Error &error);
26200
26201 // All of:
26202 // shutdown_ssl
26203 // shutdown_socket
26204 // close_socket
26205 // should ONLY be called when socket_mutex_ is locked.
26206 // Also, shutdown_ssl and close_socket should also NOT be called concurrently
26207 // with a DIFFERENT thread sending requests using that socket.
26208 virtual void shutdown_ssl(Socket &socket, bool shutdown_gracefully);
26209 void shutdown_socket(Socket &socket) const;
26210 void close_socket(Socket &socket);
26211
26212 bool process_request(Stream &strm, Request &req, Response &res,
26213 bool close_connection, Error &error);
26214
26215 bool write_content_with_provider(Stream &strm, const Request &req,
26216 Error &error) const;
26217
26218 void copy_settings(const ClientImpl &rhs);
26219
26220 // Socket endpoint information
26221 const std::string host_;
26222 const int port_;
26223 const std::string host_and_port_;
26224
26225 // Current open socket
26226 Socket socket_;
26227 mutable std::mutex socket_mutex_;
26228 std::recursive_mutex request_mutex_;
26229
26230 // These are all protected under socket_mutex
26231 size_t socket_requests_in_flight_ = 0;
26232 std::thread::id socket_requests_are_from_thread_ = std::thread::id();
26233 bool socket_should_be_closed_when_request_is_done_ = false;
26234
26235 // Hostname-IP map
26236 std::map<std::string, std::string> addr_map_;
26237
26238 // Default headers
26239 Headers default_headers_;
26240
26241 // Header writer
26242 std::function<ssize_t(Stream &, Headers &)> header_writer_ =
26243 detail::write_headers;
26244
26245 // Settings
26246 std::string client_cert_path_;
26247 std::string client_key_path_;
26248
26249 time_t connection_timeout_sec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND;
26250 time_t connection_timeout_usec_ = CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND;
26251 time_t read_timeout_sec_ = CPPHTTPLIB_READ_TIMEOUT_SECOND;
26252 time_t read_timeout_usec_ = CPPHTTPLIB_READ_TIMEOUT_USECOND;
26253 time_t write_timeout_sec_ = CPPHTTPLIB_WRITE_TIMEOUT_SECOND;
26254 time_t write_timeout_usec_ = CPPHTTPLIB_WRITE_TIMEOUT_USECOND;
26255
26256 std::string basic_auth_username_;
26257 std::string basic_auth_password_;
26258 std::string bearer_token_auth_token_;
26259#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26260 std::string digest_auth_username_;
26261 std::string digest_auth_password_;
26262#endif
26263
26264 bool keep_alive_ = false;
26265 bool follow_location_ = false;
26266
26267 bool url_encode_ = true;
26268
26269 int address_family_ = AF_UNSPEC;
26270 bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;
26271 SocketOptions socket_options_ = nullptr;
26272
26273 bool compress_ = false;
26274 bool decompress_ = true;
26275
26276 std::string interface_;
26277
26278 std::string proxy_host_;
26279 int proxy_port_ = -1;
26280
26281 std::string proxy_basic_auth_username_;
26282 std::string proxy_basic_auth_password_;
26283 std::string proxy_bearer_token_auth_token_;
26284#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26285 std::string proxy_digest_auth_username_;
26286 std::string proxy_digest_auth_password_;
26287#endif
26288
26289#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26290 std::string ca_cert_file_path_;
26291 std::string ca_cert_dir_path_;
26292
26293 X509_STORE *ca_cert_store_ = nullptr;
26294#endif
26295
26296#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26297 bool server_certificate_verification_ = true;
26298#endif
26299
26300 Logger logger_;
26301
26302private:
26303 bool send_(Request &req, Response &res, Error &error);
26304 Result send_(Request &&req);
26305
26306 socket_t create_client_socket(Error &error) const;
26307 bool read_response_line(Stream &strm, const Request &req,
26308 Response &res) const;
26309 bool write_request(Stream &strm, Request &req, bool close_connection,
26310 Error &error);
26311 bool redirect(Request &req, Response &res, Error &error);
26312 bool handle_request(Stream &strm, Request &req, Response &res,
26313 bool close_connection, Error &error);
26314 std::unique_ptr<Response> send_with_content_provider(
26315 Request &req, const char *body, size_t content_length,
26316 ContentProvider content_provider,
26317 ContentProviderWithoutLength content_provider_without_length,
26318 const std::string &content_type, Error &error, ContentReceiver content_receiver=nullptr);
26319 Result send_with_content_provider(
26320 const std::string &method, const std::string &path,
26321 const Headers &headers, const char *body, size_t content_length,
26322 ContentProvider content_provider,
26323 ContentProviderWithoutLength content_provider_without_length,
26324 const std::string &content_type, Progress progress, ContentReceiver content_receiver=nullptr);
26325 ContentProviderWithoutLength get_multipart_content_provider(
26326 const std::string &boundary, const MultipartFormDataItems &items,
26327 const MultipartFormDataProviderItems &provider_items) const;
26328
26329 std::string adjust_host_string(const std::string &host) const;
26330
26331 virtual bool process_socket(const Socket &socket,
26332 std::function<bool(Stream &strm)> callback);
26333 virtual bool is_ssl() const;
26334};
26335
26336class Client {
26337public:
26338 // Universal interface
26339 explicit Client(const std::string &scheme_host_port);
26340
26341 explicit Client(const std::string &scheme_host_port,
26342 const std::string &client_cert_path,
26343 const std::string &client_key_path);
26344
26345 // HTTP only interface
26346 explicit Client(const std::string &host, int port);
26347
26348 explicit Client(const std::string &host, int port,
26349 const std::string &client_cert_path,
26350 const std::string &client_key_path);
26351
26352 Client(Client &&) = default;
26353
26354 ~Client();
26355
26356 bool is_valid() const;
26357
26358 Result Get(const std::string &path);
26359 Result Get(const std::string &path, const Headers &headers);
26360 Result Get(const std::string &path, Progress progress);
26361 Result Get(const std::string &path, const Headers &headers,
26362 Progress progress);
26363 Result Get(const std::string &path, ContentReceiver content_receiver);
26364 Result Get(const std::string &path, const Headers &headers,
26365 ContentReceiver content_receiver);
26366 Result Get(const std::string &path, ContentReceiver content_receiver,
26367 Progress progress);
26368 Result Get(const std::string &path, const Headers &headers,
26369 ContentReceiver content_receiver, Progress progress);
26370 Result Get(const std::string &path, ResponseHandler response_handler,
26371 ContentReceiver content_receiver);
26372 Result Get(const std::string &path, const Headers &headers,
26373 ResponseHandler response_handler,
26374 ContentReceiver content_receiver);
26375 Result Get(const std::string &path, const Headers &headers,
26376 ResponseHandler response_handler, ContentReceiver content_receiver,
26377 Progress progress);
26378 Result Get(const std::string &path, ResponseHandler response_handler,
26379 ContentReceiver content_receiver, Progress progress);
26380
26381 Result Get(const std::string &path, const Params &params,
26382 const Headers &headers, Progress progress = nullptr);
26383 Result Get(const std::string &path, const Params &params,
26384 const Headers &headers, ContentReceiver content_receiver,
26385 Progress progress = nullptr);
26386 Result Get(const std::string &path, const Params &params,
26387 const Headers &headers, ResponseHandler response_handler,
26388 ContentReceiver content_receiver, Progress progress = nullptr);
26389
26390 Result Head(const std::string &path);
26391 Result Head(const std::string &path, const Headers &headers);
26392
26393 Result Post(const std::string &path);
26394 Result Post(const std::string &path, const Headers &headers);
26395 Result Post(const std::string &path, const char *body, size_t content_length,
26396 const std::string &content_type);
26397 Result Post(const std::string &path, const Headers &headers, const char *body,
26398 size_t content_length, const std::string &content_type);
26399 Result Post(const std::string &path, const Headers &headers, const char *body,
26400 size_t content_length, const std::string &content_type,
26401 Progress progress);
26402 Result Post(const std::string &path, const std::string &body,
26403 const std::string &content_type);
26404 Result Post(const std::string &path, const std::string &body,
26405 const std::string &content_type, ContentReceiver content_receiver);
26406 Result Post(const std::string &path, const std::string &body,
26407 const std::string &content_type, Progress progress);
26408 Result Post(const std::string &path, const Headers &headers,
26409 const std::string &body, const std::string &content_type);
26410 Result Post(const std::string &path, const Headers &headers,
26411 const std::string &body, const std::string &content_type,
26412 Progress progress);
26413 Result Post(const std::string &path, const Headers &headers,
26414 const std::string &body,
26415 const std::string &content_type,
26416 ContentReceiver content_receiver);
26417 Result Post(const std::string &path, size_t content_length,
26418 ContentProvider content_provider,
26419 const std::string &content_type);
26420 Result Post(const std::string &path,
26421 ContentProviderWithoutLength content_provider,
26422 const std::string &content_type);
26423 Result Post(const std::string &path, const Headers &headers,
26424 size_t content_length, ContentProvider content_provider,
26425 const std::string &content_type);
26426 Result Post(const std::string &path, const Headers &headers,
26427 ContentProviderWithoutLength content_provider,
26428 const std::string &content_type);
26429 Result Post(const std::string &path, const Params &params);
26430 Result Post(const std::string &path, const Headers &headers,
26431 const Params &params);
26432 Result Post(const std::string &path, const Headers &headers,
26433 const Params &params, Progress progress);
26434 Result Post(const std::string &path, const MultipartFormDataItems &items);
26435 Result Post(const std::string &path, const Headers &headers,
26436 const MultipartFormDataItems &items);
26437 Result Post(const std::string &path, const Headers &headers,
26438 const MultipartFormDataItems &items, const std::string &boundary);
26439 Result Post(const std::string &path, const Headers &headers,
26440 const MultipartFormDataItems &items,
26441 const MultipartFormDataProviderItems &provider_items);
26442
26443 Result Put(const std::string &path);
26444 Result Put(const std::string &path, const char *body, size_t content_length,
26445 const std::string &content_type);
26446 Result Put(const std::string &path, const Headers &headers, const char *body,
26447 size_t content_length, const std::string &content_type);
26448 Result Put(const std::string &path, const Headers &headers, const char *body,
26449 size_t content_length, const std::string &content_type,
26450 Progress progress);
26451 Result Put(const std::string &path, const std::string &body,
26452 const std::string &content_type);
26453 Result Put(const std::string &path, const std::string &body,
26454 const std::string &content_type, Progress progress);
26455 Result Put(const std::string &path, const Headers &headers,
26456 const std::string &body, const std::string &content_type);
26457 Result Put(const std::string &path, const Headers &headers,
26458 const std::string &body, const std::string &content_type,
26459 Progress progress);
26460 Result Put(const std::string &path, size_t content_length,
26461 ContentProvider content_provider, const std::string &content_type);
26462 Result Put(const std::string &path,
26463 ContentProviderWithoutLength content_provider,
26464 const std::string &content_type);
26465 Result Put(const std::string &path, const Headers &headers,
26466 size_t content_length, ContentProvider content_provider,
26467 const std::string &content_type);
26468 Result Put(const std::string &path, const Headers &headers,
26469 ContentProviderWithoutLength content_provider,
26470 const std::string &content_type);
26471 Result Put(const std::string &path, const Params &params);
26472 Result Put(const std::string &path, const Headers &headers,
26473 const Params &params);
26474 Result Put(const std::string &path, const Headers &headers,
26475 const Params &params, Progress progress);
26476 Result Put(const std::string &path, const MultipartFormDataItems &items);
26477 Result Put(const std::string &path, const Headers &headers,
26478 const MultipartFormDataItems &items);
26479 Result Put(const std::string &path, const Headers &headers,
26480 const MultipartFormDataItems &items, const std::string &boundary);
26481 Result Put(const std::string &path, const Headers &headers,
26482 const MultipartFormDataItems &items,
26483 const MultipartFormDataProviderItems &provider_items);
26484
26485 Result Patch(const std::string &path);
26486 Result Patch(const std::string &path, const char *body, size_t content_length,
26487 const std::string &content_type);
26488 Result Patch(const std::string &path, const char *body, size_t content_length,
26489 const std::string &content_type, Progress progress);
26490 Result Patch(const std::string &path, const Headers &headers,
26491 const char *body, size_t content_length,
26492 const std::string &content_type);
26493 Result Patch(const std::string &path, const Headers &headers,
26494 const char *body, size_t content_length,
26495 const std::string &content_type, Progress progress);
26496 Result Patch(const std::string &path, const std::string &body,
26497 const std::string &content_type);
26498 Result Patch(const std::string &path, const std::string &body,
26499 const std::string &content_type, Progress progress);
26500 Result Patch(const std::string &path, const Headers &headers,
26501 const std::string &body, const std::string &content_type);
26502 Result Patch(const std::string &path, const Headers &headers,
26503 const std::string &body, const std::string &content_type,
26504 Progress progress);
26505 Result Patch(const std::string &path, size_t content_length,
26506 ContentProvider content_provider,
26507 const std::string &content_type);
26508 Result Patch(const std::string &path,
26509 ContentProviderWithoutLength content_provider,
26510 const std::string &content_type);
26511 Result Patch(const std::string &path, const Headers &headers,
26512 size_t content_length, ContentProvider content_provider,
26513 const std::string &content_type);
26514 Result Patch(const std::string &path, const Headers &headers,
26515 ContentProviderWithoutLength content_provider,
26516 const std::string &content_type);
26517
26518 Result Delete(const std::string &path);
26519 Result Delete(const std::string &path, const Headers &headers);
26520 Result Delete(const std::string &path, const char *body,
26521 size_t content_length, const std::string &content_type);
26522 Result Delete(const std::string &path, const char *body,
26523 size_t content_length, const std::string &content_type,
26524 Progress progress);
26525 Result Delete(const std::string &path, const Headers &headers,
26526 const char *body, size_t content_length,
26527 const std::string &content_type);
26528 Result Delete(const std::string &path, const Headers &headers,
26529 const char *body, size_t content_length,
26530 const std::string &content_type, Progress progress);
26531 Result Delete(const std::string &path, const std::string &body,
26532 const std::string &content_type);
26533 Result Delete(const std::string &path, const std::string &body,
26534 const std::string &content_type, Progress progress);
26535 Result Delete(const std::string &path, const Headers &headers,
26536 const std::string &body, const std::string &content_type);
26537 Result Delete(const std::string &path, const Headers &headers,
26538 const std::string &body, const std::string &content_type,
26539 Progress progress);
26540
26541 Result Options(const std::string &path);
26542 Result Options(const std::string &path, const Headers &headers);
26543
26544 bool send(Request &req, Response &res, Error &error);
26545 Result send(const Request &req);
26546
26547 void stop();
26548
26549 std::string host() const;
26550 int port() const;
26551
26552 size_t is_socket_open() const;
26553 socket_t socket() const;
26554
26555 void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
26556
26557 void set_default_headers(Headers headers);
26558
26559 void
26560 set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);
26561
26562 void set_address_family(int family);
26563 void set_tcp_nodelay(bool on);
26564 void set_socket_options(SocketOptions socket_options);
26565
26566 void set_connection_timeout(time_t sec, time_t usec = 0);
26567 template <class Rep, class Period>
26568 void
26569 set_connection_timeout(const std::chrono::duration<Rep, Period> &duration);
26570
26571 void set_read_timeout(time_t sec, time_t usec = 0);
26572 template <class Rep, class Period>
26573 void set_read_timeout(const std::chrono::duration<Rep, Period> &duration);
26574
26575 void set_write_timeout(time_t sec, time_t usec = 0);
26576 template <class Rep, class Period>
26577 void set_write_timeout(const std::chrono::duration<Rep, Period> &duration);
26578
26579 void set_basic_auth(const std::string &username, const std::string &password);
26580 void set_bearer_token_auth(const std::string &token);
26581#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26582 void set_digest_auth(const std::string &username,
26583 const std::string &password);
26584#endif
26585
26586 void set_keep_alive(bool on);
26587 void set_follow_location(bool on);
26588
26589 void set_url_encode(bool on);
26590
26591 void set_compress(bool on);
26592
26593 void set_decompress(bool on);
26594
26595 void set_interface(const std::string &intf);
26596
26597 void set_proxy(const std::string &host, int port);
26598 void set_proxy_basic_auth(const std::string &username,
26599 const std::string &password);
26600 void set_proxy_bearer_token_auth(const std::string &token);
26601#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26602 void set_proxy_digest_auth(const std::string &username,
26603 const std::string &password);
26604#endif
26605
26606#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26607 void enable_server_certificate_verification(bool enabled);
26608#endif
26609
26610 void set_logger(Logger logger);
26611
26612 // SSL
26613#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26614 void set_ca_cert_path(const std::string &ca_cert_file_path,
26615 const std::string &ca_cert_dir_path = std::string());
26616
26617 void set_ca_cert_store(X509_STORE *ca_cert_store);
26618 void load_ca_cert_store(const char *ca_cert, std::size_t size);
26619
26620 long get_openssl_verify_result() const;
26621
26622 SSL_CTX *ssl_context() const;
26623#endif
26624
26625private:
26626 std::unique_ptr<ClientImpl> cli_;
26627
26628#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26629 bool is_ssl_ = false;
26630#endif
26631};
26632
26633#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
26634class SSLServer : public Server {
26635public:
26636 SSLServer(const char *cert_path, const char *private_key_path,
26637 const char *client_ca_cert_file_path = nullptr,
26638 const char *client_ca_cert_dir_path = nullptr,
26639 const char *private_key_password = nullptr);
26640
26641 SSLServer(X509 *cert, EVP_PKEY *private_key,
26642 X509_STORE *client_ca_cert_store = nullptr);
26643
26644 SSLServer(
26645 const std::function<bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback);
26646
26647 ~SSLServer() override;
26648
26649 bool is_valid() const override;
26650
26651 SSL_CTX *ssl_context() const;
26652
26653private:
26654 bool process_and_close_socket(socket_t sock) override;
26655
26656 SSL_CTX *ctx_;
26657 std::mutex ctx_mutex_;
26658};
26659
26660class SSLClient final : public ClientImpl {
26661public:
26662 explicit SSLClient(const std::string &host);
26663
26664 explicit SSLClient(const std::string &host, int port);
26665
26666 explicit SSLClient(const std::string &host, int port,
26667 const std::string &client_cert_path,
26668 const std::string &client_key_path,
26669 const std::string &private_key_password = std::string());
26670
26671 explicit SSLClient(const std::string &host, int port, X509 *client_cert,
26672 EVP_PKEY *client_key,
26673 const std::string &private_key_password = std::string());
26674
26675 ~SSLClient() override;
26676
26677 bool is_valid() const override;
26678
26679 void set_ca_cert_store(X509_STORE *ca_cert_store);
26680 void load_ca_cert_store(const char *ca_cert, std::size_t size);
26681
26682 long get_openssl_verify_result() const;
26683
26684 SSL_CTX *ssl_context() const;
26685
26686private:
26687 bool create_and_connect_socket(Socket &socket, Error &error) override;
26688 void shutdown_ssl(Socket &socket, bool shutdown_gracefully) override;
26689 void shutdown_ssl_impl(Socket &socket, bool shutdown_gracefully);
26690
26691 bool process_socket(const Socket &socket,
26692 std::function<bool(Stream &strm)> callback) override;
26693 bool is_ssl() const override;
26694
26695 bool connect_with_proxy(Socket &sock, Response &res, bool &success,
26696 Error &error);
26697 bool initialize_ssl(Socket &socket, Error &error);
26698
26699 bool load_certs();
26700
26701 bool verify_host(X509 *server_cert) const;
26702 bool verify_host_with_subject_alt_name(X509 *server_cert) const;
26703 bool verify_host_with_common_name(X509 *server_cert) const;
26704 bool check_host_name(const char *pattern, size_t pattern_len) const;
26705
26706 SSL_CTX *ctx_;
26707 std::mutex ctx_mutex_;
26708 std::once_flag initialize_cert_;
26709
26710 std::vector<std::string> host_components_;
26711
26712 long verify_result_ = 0;
26713
26714 friend class ClientImpl;
26715};
26716#endif
26717
26718/*
26719 * Implementation of template methods.
26720 */
26721
26722namespace detail {
26723
26724template <typename T, typename U>
26725inline void duration_to_sec_and_usec(const T &duration, U callback) {
26726 auto sec = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
26727 auto usec = std::chrono::duration_cast<std::chrono::microseconds>(
26728 duration - std::chrono::seconds(sec))
26729 .count();
26730 callback(static_cast<time_t>(sec), static_cast<time_t>(usec));
26731}
26732
26733inline uint64_t get_header_value_u64(const Headers &headers,
26734 const std::string &key, size_t id,
26735 uint64_t def) {
26736 auto rng = headers.equal_range(key);
26737 auto it = rng.first;
26738 std::advance(it, static_cast<ssize_t>(id));
26739 if (it != rng.second) {
26740 return std::strtoull(it->second.data(), nullptr, 10);
26741 }
26742 return def;
26743}
26744
26745} // namespace detail
26746
26747inline uint64_t Request::get_header_value_u64(const std::string &key,
26748 size_t id) const {
26749 return detail::get_header_value_u64(headers, key, id, 0);
26750}
26751
26752inline uint64_t Response::get_header_value_u64(const std::string &key,
26753 size_t id) const {
26754 return detail::get_header_value_u64(headers, key, id, 0);
26755}
26756
26757template <typename... Args>
26758inline ssize_t Stream::write_format(const char *fmt, const Args &...args) {
26759 const auto bufsiz = 2048;
26760 std::array<char, bufsiz> buf{};
26761
26762 auto sn = snprintf(buf.data(), buf.size() - 1, fmt, args...);
26763 if (sn <= 0) { return sn; }
26764
26765 auto n = static_cast<size_t>(sn);
26766
26767 if (n >= buf.size() - 1) {
26768 std::vector<char> glowable_buf(buf.size());
26769
26770 while (n >= glowable_buf.size() - 1) {
26771 glowable_buf.resize(glowable_buf.size() * 2);
26772 n = static_cast<size_t>(
26773 snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...));
26774 }
26775 return write(&glowable_buf[0], n);
26776 } else {
26777 return write(buf.data(), n);
26778 }
26779}
26780
26781inline void default_socket_options(socket_t sock) {
26782 int yes = 1;
26783#ifdef _WIN32
26784 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
26785 reinterpret_cast<const char *>(&yes), sizeof(yes));
26786 setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
26787 reinterpret_cast<const char *>(&yes), sizeof(yes));
26788#else
26789#ifdef SO_REUSEPORT
26790 setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
26791 reinterpret_cast<const void *>(&yes), sizeof(yes));
26792#else
26793 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
26794 reinterpret_cast<const void *>(&yes), sizeof(yes));
26795#endif
26796#endif
26797}
26798
26799inline const char *status_message(int status) {
26800 switch (status) {
26801 case StatusCode::Continue_100: return "Continue";
26802 case StatusCode::SwitchingProtocol_101: return "Switching Protocol";
26803 case StatusCode::Processing_102: return "Processing";
26804 case StatusCode::EarlyHints_103: return "Early Hints";
26805 case StatusCode::OK_200: return "OK";
26806 case StatusCode::Created_201: return "Created";
26807 case StatusCode::Accepted_202: return "Accepted";
26808 case StatusCode::NonAuthoritativeInformation_203:
26809 return "Non-Authoritative Information";
26810 case StatusCode::NoContent_204: return "No Content";
26811 case StatusCode::ResetContent_205: return "Reset Content";
26812 case StatusCode::PartialContent_206: return "Partial Content";
26813 case StatusCode::MultiStatus_207: return "Multi-Status";
26814 case StatusCode::AlreadyReported_208: return "Already Reported";
26815 case StatusCode::IMUsed_226: return "IM Used";
26816 case StatusCode::MultipleChoices_300: return "Multiple Choices";
26817 case StatusCode::MovedPermanently_301: return "Moved Permanently";
26818 case StatusCode::Found_302: return "Found";
26819 case StatusCode::SeeOther_303: return "See Other";
26820 case StatusCode::NotModified_304: return "Not Modified";
26821 case StatusCode::UseProxy_305: return "Use Proxy";
26822 case StatusCode::unused_306: return "unused";
26823 case StatusCode::TemporaryRedirect_307: return "Temporary Redirect";
26824 case StatusCode::PermanentRedirect_308: return "Permanent Redirect";
26825 case StatusCode::BadRequest_400: return "Bad Request";
26826 case StatusCode::Unauthorized_401: return "Unauthorized";
26827 case StatusCode::PaymentRequired_402: return "Payment Required";
26828 case StatusCode::Forbidden_403: return "Forbidden";
26829 case StatusCode::NotFound_404: return "Not Found";
26830 case StatusCode::MethodNotAllowed_405: return "Method Not Allowed";
26831 case StatusCode::NotAcceptable_406: return "Not Acceptable";
26832 case StatusCode::ProxyAuthenticationRequired_407:
26833 return "Proxy Authentication Required";
26834 case StatusCode::RequestTimeout_408: return "Request Timeout";
26835 case StatusCode::Conflict_409: return "Conflict";
26836 case StatusCode::Gone_410: return "Gone";
26837 case StatusCode::LengthRequired_411: return "Length Required";
26838 case StatusCode::PreconditionFailed_412: return "Precondition Failed";
26839 case StatusCode::PayloadTooLarge_413: return "Payload Too Large";
26840 case StatusCode::UriTooLong_414: return "URI Too Long";
26841 case StatusCode::UnsupportedMediaType_415: return "Unsupported Media Type";
26842 case StatusCode::RangeNotSatisfiable_416: return "Range Not Satisfiable";
26843 case StatusCode::ExpectationFailed_417: return "Expectation Failed";
26844 case StatusCode::ImATeapot_418: return "I'm a teapot";
26845 case StatusCode::MisdirectedRequest_421: return "Misdirected Request";
26846 case StatusCode::UnprocessableContent_422: return "Unprocessable Content";
26847 case StatusCode::Locked_423: return "Locked";
26848 case StatusCode::FailedDependency_424: return "Failed Dependency";
26849 case StatusCode::TooEarly_425: return "Too Early";
26850 case StatusCode::UpgradeRequired_426: return "Upgrade Required";
26851 case StatusCode::PreconditionRequired_428: return "Precondition Required";
26852 case StatusCode::TooManyRequests_429: return "Too Many Requests";
26853 case StatusCode::RequestHeaderFieldsTooLarge_431:
26854 return "Request Header Fields Too Large";
26855 case StatusCode::UnavailableForLegalReasons_451:
26856 return "Unavailable For Legal Reasons";
26857 case StatusCode::NotImplemented_501: return "Not Implemented";
26858 case StatusCode::BadGateway_502: return "Bad Gateway";
26859 case StatusCode::ServiceUnavailable_503: return "Service Unavailable";
26860 case StatusCode::GatewayTimeout_504: return "Gateway Timeout";
26861 case StatusCode::HttpVersionNotSupported_505:
26862 return "HTTP Version Not Supported";
26863 case StatusCode::VariantAlsoNegotiates_506: return "Variant Also Negotiates";
26864 case StatusCode::InsufficientStorage_507: return "Insufficient Storage";
26865 case StatusCode::LoopDetected_508: return "Loop Detected";
26866 case StatusCode::NotExtended_510: return "Not Extended";
26867 case StatusCode::NetworkAuthenticationRequired_511:
26868 return "Network Authentication Required";
26869
26870 default:
26871 case StatusCode::InternalServerError_500: return "Internal Server Error";
26872 }
26873}
26874
26875inline std::string get_bearer_token_auth(const Request &req) {
26876 if (req.has_header("Authorization")) {
26877 static std::string BearerHeaderPrefix = "Bearer ";
26878 return req.get_header_value("Authorization")
26879 .substr(BearerHeaderPrefix.length());
26880 }
26881 return "";
26882}
26883
26884template <class Rep, class Period>
26885inline Server &
26886Server::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
26887 detail::duration_to_sec_and_usec(
26888 duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
26889 return *this;
26890}
26891
26892template <class Rep, class Period>
26893inline Server &
26894Server::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
26895 detail::duration_to_sec_and_usec(
26896 duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
26897 return *this;
26898}
26899
26900template <class Rep, class Period>
26901inline Server &
26902Server::set_idle_interval(const std::chrono::duration<Rep, Period> &duration) {
26903 detail::duration_to_sec_and_usec(
26904 duration, [&](time_t sec, time_t usec) { set_idle_interval(sec, usec); });
26905 return *this;
26906}
26907
26908inline std::string to_string(const Error error) {
26909 switch (error) {
26910 case Error::Success: return "Success (no error)";
26911 case Error::Connection: return "Could not establish connection";
26912 case Error::BindIPAddress: return "Failed to bind IP address";
26913 case Error::Read: return "Failed to read connection";
26914 case Error::Write: return "Failed to write connection";
26915 case Error::ExceedRedirectCount: return "Maximum redirect count exceeded";
26916 case Error::Canceled: return "Connection handling canceled";
26917 case Error::SSLConnection: return "SSL connection failed";
26918 case Error::SSLLoadingCerts: return "SSL certificate loading failed";
26919 case Error::SSLServerVerification: return "SSL server verification failed";
26920 case Error::UnsupportedMultipartBoundaryChars:
26921 return "Unsupported HTTP multipart boundary characters";
26922 case Error::Compression: return "Compression failed";
26923 case Error::ConnectionTimeout: return "Connection timed out";
26924 case Error::ProxyConnection: return "Proxy connection failed";
26925 case Error::Unknown: return "Unknown";
26926 default: break;
26927 }
26928
26929 return "Invalid";
26930}
26931
26932inline std::ostream &operator<<(std::ostream &os, const Error &obj) {
26933 os << to_string(obj);
26934 os << " (" << static_cast<std::underlying_type<Error>::type>(obj) << ')';
26935 return os;
26936}
26937
26938inline uint64_t Result::get_request_header_value_u64(const std::string &key,
26939 size_t id) const {
26940 return detail::get_header_value_u64(request_headers_, key, id, 0);
26941}
26942
26943template <class Rep, class Period>
26944inline void ClientImpl::set_connection_timeout(
26945 const std::chrono::duration<Rep, Period> &duration) {
26946 detail::duration_to_sec_and_usec(duration, [&](time_t sec, time_t usec) {
26947 set_connection_timeout(sec, usec);
26948 });
26949}
26950
26951template <class Rep, class Period>
26952inline void ClientImpl::set_read_timeout(
26953 const std::chrono::duration<Rep, Period> &duration) {
26954 detail::duration_to_sec_and_usec(
26955 duration, [&](time_t sec, time_t usec) { set_read_timeout(sec, usec); });
26956}
26957
26958template <class Rep, class Period>
26959inline void ClientImpl::set_write_timeout(
26960 const std::chrono::duration<Rep, Period> &duration) {
26961 detail::duration_to_sec_and_usec(
26962 duration, [&](time_t sec, time_t usec) { set_write_timeout(sec, usec); });
26963}
26964
26965template <class Rep, class Period>
26966inline void Client::set_connection_timeout(
26967 const std::chrono::duration<Rep, Period> &duration) {
26968 cli_->set_connection_timeout(duration);
26969}
26970
26971template <class Rep, class Period>
26972inline void
26973Client::set_read_timeout(const std::chrono::duration<Rep, Period> &duration) {
26974 cli_->set_read_timeout(duration);
26975}
26976
26977template <class Rep, class Period>
26978inline void
26979Client::set_write_timeout(const std::chrono::duration<Rep, Period> &duration) {
26980 cli_->set_write_timeout(duration);
26981}
26982
26983/*
26984 * Forward declarations and types that will be part of the .h file if split into
26985 * .h + .cc.
26986 */
26987
26988std::string hosted_at(const std::string &hostname);
26989
26990void hosted_at(const std::string &hostname, std::vector<std::string> &addrs);
26991
26992std::string append_query_params(const std::string &path, const Params &params);
26993
26994std::pair<std::string, std::string> make_range_header(const Ranges &ranges);
26995
26996std::pair<std::string, std::string>
26997make_basic_authentication_header(const std::string &username,
26998 const std::string &password,
26999 bool is_proxy = false);
27000
27001namespace detail {
27002
27003std::string encode_query_param(const std::string &value);
27004
27005std::string decode_url(const std::string &s, bool convert_plus_to_space);
27006
27007void read_file(const std::string &path, std::string &out);
27008
27009std::string trim_copy(const std::string &s);
27010
27011void divide(
27012 const char *data, std::size_t size, char d,
27013 std::function<void(const char *, std::size_t, const char *, std::size_t)>
27014 fn);
27015
27016void divide(
27017 const std::string &str, char d,
27018 std::function<void(const char *, std::size_t, const char *, std::size_t)>
27019 fn);
27020
27021void split(const char *b, const char *e, char d,
27022 std::function<void(const char *, const char *)> fn);
27023
27024void split(const char *b, const char *e, char d, size_t m,
27025 std::function<void(const char *, const char *)> fn);
27026
27027bool process_client_socket(socket_t sock, time_t read_timeout_sec,
27028 time_t read_timeout_usec, time_t write_timeout_sec,
27029 time_t write_timeout_usec,
27030 std::function<bool(Stream &)> callback);
27031
27032socket_t create_client_socket(
27033 const std::string &host, const std::string &ip, int port,
27034 int address_family, bool tcp_nodelay, SocketOptions socket_options,
27035 time_t connection_timeout_sec, time_t connection_timeout_usec,
27036 time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
27037 time_t write_timeout_usec, const std::string &intf, Error &error);
27038
27039const char *get_header_value(const Headers &headers, const std::string &key,
27040 size_t id = 0, const char *def = nullptr);
27041
27042std::string params_to_query_str(const Params &params);
27043
27044void parse_query_text(const char *data, std::size_t size, Params &params);
27045
27046void parse_query_text(const std::string &s, Params &params);
27047
27048bool parse_multipart_boundary(const std::string &content_type,
27049 std::string &boundary);
27050
27051bool parse_range_header(const std::string &s, Ranges &ranges);
27052
27053int close_socket(socket_t sock);
27054
27055ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags);
27056
27057ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags);
27058
27059enum class EncodingType { None = 0, Gzip, Brotli };
27060
27061EncodingType encoding_type(const Request &req, const Response &res);
27062
27063class BufferStream final : public Stream {
27064public:
27065 BufferStream() = default;
27066 ~BufferStream() override = default;
27067
27068 bool is_readable() const override;
27069 bool is_writable() const override;
27070 ssize_t read(char *ptr, size_t size) override;
27071 ssize_t write(const char *ptr, size_t size) override;
27072 void get_remote_ip_and_port(std::string &ip, int &port) const override;
27073 void get_local_ip_and_port(std::string &ip, int &port) const override;
27074 socket_t socket() const override;
27075
27076 const std::string &get_buffer() const;
27077
27078private:
27079 std::string buffer;
27080 size_t position = 0;
27081};
27082
27084public:
27085 virtual ~compressor() = default;
27086
27087 typedef std::function<bool(const char *data, size_t data_len)> Callback;
27088 virtual bool compress(const char *data, size_t data_length, bool last,
27089 Callback callback) = 0;
27090};
27091
27093public:
27094 virtual ~decompressor() = default;
27095
27096 virtual bool is_valid() const = 0;
27097
27098 typedef std::function<bool(const char *data, size_t data_len)> Callback;
27099 virtual bool decompress(const char *data, size_t data_length,
27100 Callback callback) = 0;
27101};
27102
27103class nocompressor final : public compressor {
27104public:
27105 ~nocompressor() override = default;
27106
27107 bool compress(const char *data, size_t data_length, bool /*last*/,
27108 Callback callback) override;
27109};
27110
27111#ifdef CPPHTTPLIB_ZLIB_SUPPORT
27112class gzip_compressor final : public compressor {
27113public:
27114 gzip_compressor();
27115 ~gzip_compressor() override;
27116
27117 bool compress(const char *data, size_t data_length, bool last,
27118 Callback callback) override;
27119
27120private:
27121 bool is_valid_ = false;
27122 z_stream strm_;
27123};
27124
27125class gzip_decompressor final : public decompressor {
27126public:
27127 gzip_decompressor();
27128 ~gzip_decompressor() override;
27129
27130 bool is_valid() const override;
27131
27132 bool decompress(const char *data, size_t data_length,
27133 Callback callback) override;
27134
27135private:
27136 bool is_valid_ = false;
27137 z_stream strm_;
27138};
27139#endif
27140
27141#ifdef CPPHTTPLIB_BROTLI_SUPPORT
27142class brotli_compressor final : public compressor {
27143public:
27144 brotli_compressor();
27145 ~brotli_compressor();
27146
27147 bool compress(const char *data, size_t data_length, bool last,
27148 Callback callback) override;
27149
27150private:
27151 BrotliEncoderState *state_ = nullptr;
27152};
27153
27154class brotli_decompressor final : public decompressor {
27155public:
27156 brotli_decompressor();
27157 ~brotli_decompressor();
27158
27159 bool is_valid() const override;
27160
27161 bool decompress(const char *data, size_t data_length,
27162 Callback callback) override;
27163
27164private:
27165 BrotliDecoderResult decoder_r;
27166 BrotliDecoderState *decoder_s = nullptr;
27167};
27168#endif
27169
27170// NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer`
27171// to store data. The call can set memory on stack for performance.
27173public:
27174 stream_line_reader(Stream &strm, char *fixed_buffer,
27175 size_t fixed_buffer_size);
27176 const char *ptr() const;
27177 size_t size() const;
27178 bool end_with_crlf() const;
27179 bool getline();
27180
27181private:
27182 void append(char c);
27183
27184 Stream &strm_;
27185 char *fixed_buffer_;
27186 const size_t fixed_buffer_size_;
27187 size_t fixed_buffer_used_size_ = 0;
27188 std::string glowable_buffer_;
27189};
27190
27191class mmap {
27192public:
27193 mmap(const char *path);
27194 ~mmap();
27195
27196 bool open(const char *path);
27197 void close();
27198
27199 bool is_open() const;
27200 size_t size() const;
27201 const char *data() const;
27202
27203private:
27204#if defined(_WIN32)
27205 HANDLE hFile_;
27206 HANDLE hMapping_;
27207#else
27208 int fd_;
27209#endif
27210 size_t size_;
27211 void *addr_;
27212};
27213
27214} // namespace detail
27215
27216// ----------------------------------------------------------------------------
27217
27218/*
27219 * Implementation that will be part of the .cc file if split into .h + .cc.
27220 */
27221
27222namespace detail {
27223
27224inline bool is_hex(char c, int &v) {
27225 if (0x20 <= c && isdigit(c)) {
27226 v = c - '0';
27227 return true;
27228 } else if ('A' <= c && c <= 'F') {
27229 v = c - 'A' + 10;
27230 return true;
27231 } else if ('a' <= c && c <= 'f') {
27232 v = c - 'a' + 10;
27233 return true;
27234 }
27235 return false;
27236}
27237
27238inline bool from_hex_to_i(const std::string &s, size_t i, size_t cnt,
27239 int &val) {
27240 if (i >= s.size()) { return false; }
27241
27242 val = 0;
27243 for (; cnt; i++, cnt--) {
27244 if (!s[i]) { return false; }
27245 auto v = 0;
27246 if (is_hex(s[i], v)) {
27247 val = val * 16 + v;
27248 } else {
27249 return false;
27250 }
27251 }
27252 return true;
27253}
27254
27255inline std::string from_i_to_hex(size_t n) {
27256 static const auto charset = "0123456789abcdef";
27257 std::string ret;
27258 do {
27259 ret = charset[n & 15] + ret;
27260 n >>= 4;
27261 } while (n > 0);
27262 return ret;
27263}
27264
27265inline size_t to_utf8(int code, char *buff) {
27266 if (code < 0x0080) {
27267 buff[0] = static_cast<char>(code & 0x7F);
27268 return 1;
27269 } else if (code < 0x0800) {
27270 buff[0] = static_cast<char>(0xC0 | ((code >> 6) & 0x1F));
27271 buff[1] = static_cast<char>(0x80 | (code & 0x3F));
27272 return 2;
27273 } else if (code < 0xD800) {
27274 buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
27275 buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
27276 buff[2] = static_cast<char>(0x80 | (code & 0x3F));
27277 return 3;
27278 } else if (code < 0xE000) { // D800 - DFFF is invalid...
27279 return 0;
27280 } else if (code < 0x10000) {
27281 buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));
27282 buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
27283 buff[2] = static_cast<char>(0x80 | (code & 0x3F));
27284 return 3;
27285 } else if (code < 0x110000) {
27286 buff[0] = static_cast<char>(0xF0 | ((code >> 18) & 0x7));
27287 buff[1] = static_cast<char>(0x80 | ((code >> 12) & 0x3F));
27288 buff[2] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));
27289 buff[3] = static_cast<char>(0x80 | (code & 0x3F));
27290 return 4;
27291 }
27292
27293 // NOTREACHED
27294 return 0;
27295}
27296
27297// NOTE: This code came up with the following stackoverflow post:
27298// https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c
27299inline std::string base64_encode(const std::string &in) {
27300 static const auto lookup =
27301 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
27302
27303 std::string out;
27304 out.reserve(in.size());
27305
27306 auto val = 0;
27307 auto valb = -6;
27308
27309 for (auto c : in) {
27310 val = (val << 8) + static_cast<uint8_t>(c);
27311 valb += 8;
27312 while (valb >= 0) {
27313 out.push_back(lookup[(val >> valb) & 0x3F]);
27314 valb -= 6;
27315 }
27316 }
27317
27318 if (valb > -6) { out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); }
27319
27320 while (out.size() % 4) {
27321 out.push_back('=');
27322 }
27323
27324 return out;
27325}
27326
27327inline bool is_file(const std::string &path) {
27328#ifdef _WIN32
27329 return _access_s(path.c_str(), 0) == 0;
27330#else
27331 struct stat st;
27332 return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode);
27333#endif
27334}
27335
27336inline bool is_dir(const std::string &path) {
27337 struct stat st;
27338 return stat(path.c_str(), &st) >= 0 && S_ISDIR(st.st_mode);
27339}
27340
27341inline bool is_valid_path(const std::string &path) {
27342 size_t level = 0;
27343 size_t i = 0;
27344
27345 // Skip slash
27346 while (i < path.size() && path[i] == '/') {
27347 i++;
27348 }
27349
27350 while (i < path.size()) {
27351 // Read component
27352 auto beg = i;
27353 while (i < path.size() && path[i] != '/') {
27354 if (path[i] == '\0') {
27355 return false;
27356 } else if (path[i] == '\\') {
27357 return false;
27358 }
27359 i++;
27360 }
27361
27362 auto len = i - beg;
27363 assert(len > 0);
27364
27365 if (!path.compare(beg, len, ".")) {
27366 ;
27367 } else if (!path.compare(beg, len, "..")) {
27368 if (level == 0) { return false; }
27369 level--;
27370 } else {
27371 level++;
27372 }
27373
27374 // Skip slash
27375 while (i < path.size() && path[i] == '/') {
27376 i++;
27377 }
27378 }
27379
27380 return true;
27381}
27382
27383inline std::string encode_query_param(const std::string &value) {
27384 std::ostringstream escaped;
27385 escaped.fill('0');
27386 escaped << std::hex;
27387
27388 for (auto c : value) {
27389 if (std::isalnum(static_cast<uint8_t>(c)) || c == '-' || c == '_' ||
27390 c == '.' || c == '!' || c == '~' || c == '*' || c == '\'' || c == '(' ||
27391 c == ')') {
27392 escaped << c;
27393 } else {
27394 escaped << std::uppercase;
27395 escaped << '%' << std::setw(2)
27396 << static_cast<int>(static_cast<unsigned char>(c));
27397 escaped << std::nouppercase;
27398 }
27399 }
27400
27401 return escaped.str();
27402}
27403
27404inline std::string encode_url(const std::string &s) {
27405 std::string result;
27406 result.reserve(s.size());
27407
27408 for (size_t i = 0; s[i]; i++) {
27409 switch (s[i]) {
27410 case ' ': result += "%20"; break;
27411 case '+': result += "%2B"; break;
27412 case '\r': result += "%0D"; break;
27413 case '\n': result += "%0A"; break;
27414 case '\'': result += "%27"; break;
27415 case ',': result += "%2C"; break;
27416 // case ':': result += "%3A"; break; // ok? probably...
27417 case ';': result += "%3B"; break;
27418 default:
27419 auto c = static_cast<uint8_t>(s[i]);
27420 if (c >= 0x80) {
27421 result += '%';
27422 char hex[4];
27423 auto len = snprintf(hex, sizeof(hex) - 1, "%02X", c);
27424 assert(len == 2);
27425 result.append(hex, static_cast<size_t>(len));
27426 } else {
27427 result += s[i];
27428 }
27429 break;
27430 }
27431 }
27432
27433 return result;
27434}
27435
27436inline std::string decode_url(const std::string &s,
27437 bool convert_plus_to_space) {
27438 std::string result;
27439
27440 for (size_t i = 0; i < s.size(); i++) {
27441 if (s[i] == '%' && i + 1 < s.size()) {
27442 if (s[i + 1] == 'u') {
27443 auto val = 0;
27444 if (from_hex_to_i(s, i + 2, 4, val)) {
27445 // 4 digits Unicode codes
27446 char buff[4];
27447 size_t len = to_utf8(val, buff);
27448 if (len > 0) { result.append(buff, len); }
27449 i += 5; // 'u0000'
27450 } else {
27451 result += s[i];
27452 }
27453 } else {
27454 auto val = 0;
27455 if (from_hex_to_i(s, i + 1, 2, val)) {
27456 // 2 digits hex codes
27457 result += static_cast<char>(val);
27458 i += 2; // '00'
27459 } else {
27460 result += s[i];
27461 }
27462 }
27463 } else if (convert_plus_to_space && s[i] == '+') {
27464 result += ' ';
27465 } else {
27466 result += s[i];
27467 }
27468 }
27469
27470 return result;
27471}
27472
27473inline void read_file(const std::string &path, std::string &out) {
27474 std::ifstream fs(path, std::ios_base::binary);
27475 fs.seekg(0, std::ios_base::end);
27476 auto size = fs.tellg();
27477 fs.seekg(0);
27478 out.resize(static_cast<size_t>(size));
27479 fs.read(&out[0], static_cast<std::streamsize>(size));
27480}
27481
27482inline std::string file_extension(const std::string &path) {
27483 std::smatch m;
27484 static auto re = std::regex("\\.([a-zA-Z0-9]+)$");
27485 if (std::regex_search(path, m, re)) { return m[1].str(); }
27486 return std::string();
27487}
27488
27489inline bool is_space_or_tab(char c) { return c == ' ' || c == '\t'; }
27490
27491inline std::pair<size_t, size_t> trim(const char *b, const char *e, size_t left,
27492 size_t right) {
27493 while (b + left < e && is_space_or_tab(b[left])) {
27494 left++;
27495 }
27496 while (right > 0 && is_space_or_tab(b[right - 1])) {
27497 right--;
27498 }
27499 return std::make_pair(left, right);
27500}
27501
27502inline std::string trim_copy(const std::string &s) {
27503 auto r = trim(s.data(), s.data() + s.size(), 0, s.size());
27504 return s.substr(r.first, r.second - r.first);
27505}
27506
27507inline std::string trim_double_quotes_copy(const std::string &s) {
27508 if (s.length() >= 2 && s.front() == '"' && s.back() == '"') {
27509 return s.substr(1, s.size() - 2);
27510 }
27511 return s;
27512}
27513
27514inline void
27515divide(const char *data, std::size_t size, char d,
27516 std::function<void(const char *, std::size_t, const char *, std::size_t)>
27517 fn) {
27518 const auto it = std::find(data, data + size, d);
27519 const auto found = static_cast<std::size_t>(it != data + size);
27520 const auto lhs_data = data;
27521 const auto lhs_size = static_cast<std::size_t>(it - data);
27522 const auto rhs_data = it + found;
27523 const auto rhs_size = size - lhs_size - found;
27524
27525 fn(lhs_data, lhs_size, rhs_data, rhs_size);
27526}
27527
27528inline void
27529divide(const std::string &str, char d,
27530 std::function<void(const char *, std::size_t, const char *, std::size_t)>
27531 fn) {
27532 divide(str.data(), str.size(), d, std::move(fn));
27533}
27534
27535inline void split(const char *b, const char *e, char d,
27536 std::function<void(const char *, const char *)> fn) {
27537 return split(b, e, d, (std::numeric_limits<size_t>::max)(), std::move(fn));
27538}
27539
27540inline void split(const char *b, const char *e, char d, size_t m,
27541 std::function<void(const char *, const char *)> fn) {
27542 size_t i = 0;
27543 size_t beg = 0;
27544 size_t count = 1;
27545
27546 while (e ? (b + i < e) : (b[i] != '\0')) {
27547 if (b[i] == d && count < m) {
27548 auto r = trim(b, e, beg, i);
27549 if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
27550 beg = i + 1;
27551 count++;
27552 }
27553 i++;
27554 }
27555
27556 if (i) {
27557 auto r = trim(b, e, beg, i);
27558 if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
27559 }
27560}
27561
27562inline stream_line_reader::stream_line_reader(Stream &strm, char *fixed_buffer,
27563 size_t fixed_buffer_size)
27564 : strm_(strm), fixed_buffer_(fixed_buffer),
27565 fixed_buffer_size_(fixed_buffer_size) {}
27566
27567inline const char *stream_line_reader::ptr() const {
27568 if (glowable_buffer_.empty()) {
27569 return fixed_buffer_;
27570 } else {
27571 return glowable_buffer_.data();
27572 }
27573}
27574
27575inline size_t stream_line_reader::size() const {
27576 if (glowable_buffer_.empty()) {
27577 return fixed_buffer_used_size_;
27578 } else {
27579 return glowable_buffer_.size();
27580 }
27581}
27582
27583inline bool stream_line_reader::end_with_crlf() const {
27584 auto end = ptr() + size();
27585 return size() >= 2 && end[-2] == '\r' && end[-1] == '\n';
27586}
27587
27588inline bool stream_line_reader::getline() {
27589 fixed_buffer_used_size_ = 0;
27590 glowable_buffer_.clear();
27591
27592 for (size_t i = 0;; i++) {
27593 char byte;
27594 auto n = strm_.read(&byte, 1);
27595
27596 if (n < 0) {
27597 return false;
27598 } else if (n == 0) {
27599 if (i == 0) {
27600 return false;
27601 } else {
27602 break;
27603 }
27604 }
27605
27606 append(byte);
27607
27608 if (byte == '\n') { break; }
27609 }
27610
27611 return true;
27612}
27613
27614inline void stream_line_reader::append(char c) {
27615 if (fixed_buffer_used_size_ < fixed_buffer_size_ - 1) {
27616 fixed_buffer_[fixed_buffer_used_size_++] = c;
27617 fixed_buffer_[fixed_buffer_used_size_] = '\0';
27618 } else {
27619 if (glowable_buffer_.empty()) {
27620 assert(fixed_buffer_[fixed_buffer_used_size_] == '\0');
27621 glowable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_);
27622 }
27623 glowable_buffer_ += c;
27624 }
27625}
27626
27627inline mmap::mmap(const char *path)
27628#if defined(_WIN32)
27629 : hFile_(NULL), hMapping_(NULL)
27630#else
27631 : fd_(-1)
27632#endif
27633 ,
27634 size_(0), addr_(nullptr) {
27635 open(path);
27636}
27637
27638inline mmap::~mmap() { close(); }
27639
27640inline bool mmap::open(const char *path) {
27641 close();
27642
27643#if defined(_WIN32)
27644 std::wstring wpath;
27645 for (size_t i = 0; i < strlen(path); i++) {
27646 wpath += path[i];
27647 }
27648
27649 hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
27650 OPEN_EXISTING, NULL);
27651
27652 if (hFile_ == INVALID_HANDLE_VALUE) { return false; }
27653
27654 LARGE_INTEGER size{};
27655 if (!::GetFileSizeEx(hFile_, &size)) { return false; }
27656 size_ = static_cast<size_t>(size.QuadPart);
27657
27658 hMapping_ =
27659 ::CreateFileMappingFromApp(hFile_, NULL, PAGE_READONLY, size_, NULL);
27660
27661 if (hMapping_ == NULL) {
27662 close();
27663 return false;
27664 }
27665
27666 addr_ = ::MapViewOfFileFromApp(hMapping_, FILE_MAP_READ, 0, 0);
27667#else
27668 fd_ = ::open(path, O_RDONLY);
27669 if (fd_ == -1) { return false; }
27670
27671 struct stat sb;
27672 if (fstat(fd_, &sb) == -1) {
27673 close();
27674 return false;
27675 }
27676 size_ = static_cast<size_t>(sb.st_size);
27677
27678 addr_ = ::mmap(NULL, size_, PROT_READ, MAP_PRIVATE, fd_, 0);
27679#endif
27680
27681 if (addr_ == nullptr) {
27682 close();
27683 return false;
27684 }
27685
27686 return true;
27687}
27688
27689inline bool mmap::is_open() const { return addr_ != nullptr; }
27690
27691inline size_t mmap::size() const { return size_; }
27692
27693inline const char *mmap::data() const {
27694 return static_cast<const char *>(addr_);
27695}
27696
27697inline void mmap::close() {
27698#if defined(_WIN32)
27699 if (addr_) {
27700 ::UnmapViewOfFile(addr_);
27701 addr_ = nullptr;
27702 }
27703
27704 if (hMapping_) {
27705 ::CloseHandle(hMapping_);
27706 hMapping_ = NULL;
27707 }
27708
27709 if (hFile_ != INVALID_HANDLE_VALUE) {
27710 ::CloseHandle(hFile_);
27711 hFile_ = INVALID_HANDLE_VALUE;
27712 }
27713#else
27714 if (addr_ != nullptr) {
27715 munmap(addr_, size_);
27716 addr_ = nullptr;
27717 }
27718
27719 if (fd_ != -1) {
27720 ::close(fd_);
27721 fd_ = -1;
27722 }
27723#endif
27724 size_ = 0;
27725}
27726inline int close_socket(socket_t sock) {
27727#ifdef _WIN32
27728 return closesocket(sock);
27729#else
27730 return close(sock);
27731#endif
27732}
27733
27734template <typename T> inline ssize_t handle_EINTR(T fn) {
27735 ssize_t res = 0;
27736 while (true) {
27737 res = fn();
27738 if (res < 0 && errno == EINTR) { continue; }
27739 break;
27740 }
27741 return res;
27742}
27743
27744inline ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags) {
27745 return handle_EINTR([&]() {
27746 return recv(sock,
27747#ifdef _WIN32
27748 static_cast<char *>(ptr), static_cast<int>(size),
27749#else
27750 ptr, size,
27751#endif
27752 flags);
27753 });
27754}
27755
27756inline ssize_t send_socket(socket_t sock, const void *ptr, size_t size,
27757 int flags) {
27758 return handle_EINTR([&]() {
27759 return send(sock,
27760#ifdef _WIN32
27761 static_cast<const char *>(ptr), static_cast<int>(size),
27762#else
27763 ptr, size,
27764#endif
27765 flags);
27766 });
27767}
27768
27769inline ssize_t select_read(socket_t sock, time_t sec, time_t usec) {
27770#ifdef CPPHTTPLIB_USE_POLL
27771 struct pollfd pfd_read;
27772 pfd_read.fd = sock;
27773 pfd_read.events = POLLIN;
27774
27775 auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
27776
27777 return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
27778#else
27779#ifndef _WIN32
27780 if (sock >= FD_SETSIZE) { return -1; }
27781#endif
27782
27783 fd_set fds;
27784 FD_ZERO(&fds);
27785 FD_SET(sock, &fds);
27786
27787 timeval tv;
27788 tv.tv_sec = static_cast<long>(sec);
27789 tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
27790
27791 return handle_EINTR([&]() {
27792 return select(static_cast<int>(sock + 1), &fds, nullptr, nullptr, &tv);
27793 });
27794#endif
27795}
27796
27797inline ssize_t select_write(socket_t sock, time_t sec, time_t usec) {
27798#ifdef CPPHTTPLIB_USE_POLL
27799 struct pollfd pfd_read;
27800 pfd_read.fd = sock;
27801 pfd_read.events = POLLOUT;
27802
27803 auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
27804
27805 return handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
27806#else
27807#ifndef _WIN32
27808 if (sock >= FD_SETSIZE) { return -1; }
27809#endif
27810
27811 fd_set fds;
27812 FD_ZERO(&fds);
27813 FD_SET(sock, &fds);
27814
27815 timeval tv;
27816 tv.tv_sec = static_cast<long>(sec);
27817 tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
27818
27819 return handle_EINTR([&]() {
27820 return select(static_cast<int>(sock + 1), nullptr, &fds, nullptr, &tv);
27821 });
27822#endif
27823}
27824
27825inline Error wait_until_socket_is_ready(socket_t sock, time_t sec,
27826 time_t usec) {
27827#ifdef CPPHTTPLIB_USE_POLL
27828 struct pollfd pfd_read;
27829 pfd_read.fd = sock;
27830 pfd_read.events = POLLIN | POLLOUT;
27831
27832 auto timeout = static_cast<int>(sec * 1000 + usec / 1000);
27833
27834 auto poll_res = handle_EINTR([&]() { return poll(&pfd_read, 1, timeout); });
27835
27836 if (poll_res == 0) { return Error::ConnectionTimeout; }
27837
27838 if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) {
27839 auto error = 0;
27840 socklen_t len = sizeof(error);
27841 auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
27842 reinterpret_cast<char *>(&error), &len);
27843 auto successful = res >= 0 && !error;
27844 return successful ? Error::Success : Error::Connection;
27845 }
27846
27847 return Error::Connection;
27848#else
27849#ifndef _WIN32
27850 if (sock >= FD_SETSIZE) { return Error::Connection; }
27851#endif
27852
27853 fd_set fdsr;
27854 FD_ZERO(&fdsr);
27855 FD_SET(sock, &fdsr);
27856
27857 auto fdsw = fdsr;
27858 auto fdse = fdsr;
27859
27860 timeval tv;
27861 tv.tv_sec = static_cast<long>(sec);
27862 tv.tv_usec = static_cast<decltype(tv.tv_usec)>(usec);
27863
27864 auto ret = handle_EINTR([&]() {
27865 return select(static_cast<int>(sock + 1), &fdsr, &fdsw, &fdse, &tv);
27866 });
27867
27868 if (ret == 0) { return Error::ConnectionTimeout; }
27869
27870 if (ret > 0 && (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw))) {
27871 auto error = 0;
27872 socklen_t len = sizeof(error);
27873 auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
27874 reinterpret_cast<char *>(&error), &len);
27875 auto successful = res >= 0 && !error;
27876 return successful ? Error::Success : Error::Connection;
27877 }
27878 return Error::Connection;
27879#endif
27880}
27881
27882inline bool is_socket_alive(socket_t sock) {
27883 const auto val = detail::select_read(sock, 0, 0);
27884 if (val == 0) {
27885 return true;
27886 } else if (val < 0 && errno == EBADF) {
27887 return false;
27888 }
27889 char buf[1];
27890 return detail::read_socket(sock, &buf[0], sizeof(buf), MSG_PEEK) > 0;
27891}
27892
27893class SocketStream final : public Stream {
27894public:
27895 SocketStream(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec,
27896 time_t write_timeout_sec, time_t write_timeout_usec);
27897 ~SocketStream() override;
27898
27899 bool is_readable() const override;
27900 bool is_writable() const override;
27901 ssize_t read(char *ptr, size_t size) override;
27902 ssize_t write(const char *ptr, size_t size) override;
27903 void get_remote_ip_and_port(std::string &ip, int &port) const override;
27904 void get_local_ip_and_port(std::string &ip, int &port) const override;
27905 socket_t socket() const override;
27906
27907private:
27908 socket_t sock_;
27909 time_t read_timeout_sec_;
27910 time_t read_timeout_usec_;
27911 time_t write_timeout_sec_;
27912 time_t write_timeout_usec_;
27913
27914 std::vector<char> read_buff_;
27915 size_t read_buff_off_ = 0;
27916 size_t read_buff_content_size_ = 0;
27917
27918 static const size_t read_buff_size_ = 1024l * 4;
27919};
27920
27921#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
27922class SSLSocketStream final : public Stream {
27923public:
27924 SSLSocketStream(socket_t sock, SSL *ssl, time_t read_timeout_sec,
27925 time_t read_timeout_usec, time_t write_timeout_sec,
27926 time_t write_timeout_usec);
27927 ~SSLSocketStream() override;
27928
27929 bool is_readable() const override;
27930 bool is_writable() const override;
27931 ssize_t read(char *ptr, size_t size) override;
27932 ssize_t write(const char *ptr, size_t size) override;
27933 void get_remote_ip_and_port(std::string &ip, int &port) const override;
27934 void get_local_ip_and_port(std::string &ip, int &port) const override;
27935 socket_t socket() const override;
27936
27937private:
27938 socket_t sock_;
27939 SSL *ssl_;
27940 time_t read_timeout_sec_;
27941 time_t read_timeout_usec_;
27942 time_t write_timeout_sec_;
27943 time_t write_timeout_usec_;
27944};
27945#endif
27946
27947inline bool keep_alive(socket_t sock, time_t keep_alive_timeout_sec) {
27948 using namespace std::chrono;
27949 auto start = steady_clock::now();
27950 while (true) {
27951 auto val = select_read(sock, 0, 10000);
27952 if (val < 0) {
27953 return false;
27954 } else if (val == 0) {
27955 auto current = steady_clock::now();
27956 auto duration = duration_cast<milliseconds>(current - start);
27957 auto timeout = keep_alive_timeout_sec * 1000;
27958 if (duration.count() > timeout) { return false; }
27959 std::this_thread::sleep_for(std::chrono::milliseconds(1));
27960 } else {
27961 return true;
27962 }
27963 }
27964}
27965
27966template <typename T>
27967inline bool
27968process_server_socket_core(const std::atomic<socket_t> &svr_sock, socket_t sock,
27969 size_t keep_alive_max_count,
27970 time_t keep_alive_timeout_sec, T callback) {
27971 assert(keep_alive_max_count > 0);
27972 auto ret = false;
27973 auto count = keep_alive_max_count;
27974 while (svr_sock != INVALID_SOCKET && count > 0 &&
27975 keep_alive(sock, keep_alive_timeout_sec)) {
27976 auto close_connection = count == 1;
27977 auto connection_closed = false;
27978 ret = callback(close_connection, connection_closed);
27979 if (!ret || connection_closed) { break; }
27980 count--;
27981 }
27982 return ret;
27983}
27984
27985template <typename T>
27986inline bool
27987process_server_socket(const std::atomic<socket_t> &svr_sock, socket_t sock,
27988 size_t keep_alive_max_count,
27989 time_t keep_alive_timeout_sec, time_t read_timeout_sec,
27990 time_t read_timeout_usec, time_t write_timeout_sec,
27991 time_t write_timeout_usec, T callback) {
27992 return process_server_socket_core(
27993 svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec,
27994 [&](bool close_connection, bool &connection_closed) {
27995 SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
27996 write_timeout_sec, write_timeout_usec);
27997 return callback(strm, close_connection, connection_closed);
27998 });
27999}
28000
28001inline bool process_client_socket(socket_t sock, time_t read_timeout_sec,
28002 time_t read_timeout_usec,
28003 time_t write_timeout_sec,
28004 time_t write_timeout_usec,
28005 std::function<bool(Stream &)> callback) {
28006 SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
28007 write_timeout_sec, write_timeout_usec);
28008 return callback(strm);
28009}
28010
28011inline int shutdown_socket(socket_t sock) {
28012#ifdef _WIN32
28013 return shutdown(sock, SD_BOTH);
28014#else
28015 return shutdown(sock, SHUT_RDWR);
28016#endif
28017}
28018
28019template <typename BindOrConnect>
28020socket_t create_socket(const std::string &host, const std::string &ip, int port,
28021 int address_family, int socket_flags, bool tcp_nodelay,
28022 SocketOptions socket_options,
28023 BindOrConnect bind_or_connect) {
28024 // Get address info
28025 const char *node = nullptr;
28026 struct addrinfo hints;
28027 struct addrinfo *result;
28028
28029 memset(&hints, 0, sizeof(struct addrinfo));
28030 hints.ai_socktype = SOCK_STREAM;
28031 hints.ai_protocol = 0;
28032
28033 if (!ip.empty()) {
28034 node = ip.c_str();
28035 // Ask getaddrinfo to convert IP in c-string to address
28036 hints.ai_family = AF_UNSPEC;
28037 hints.ai_flags = AI_NUMERICHOST;
28038 } else {
28039 if (!host.empty()) { node = host.c_str(); }
28040 hints.ai_family = address_family;
28041 hints.ai_flags = socket_flags;
28042 }
28043
28044#ifndef _WIN32
28045 if (hints.ai_family == AF_UNIX) {
28046 const auto addrlen = host.length();
28047 if (addrlen > sizeof(sockaddr_un::sun_path)) { return INVALID_SOCKET; }
28048
28049 auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
28050 if (sock != INVALID_SOCKET) {
28051 sockaddr_un addr{};
28052 addr.sun_family = AF_UNIX;
28053 std::copy(host.begin(), host.end(), addr.sun_path);
28054
28055 hints.ai_addr = reinterpret_cast<sockaddr *>(&addr);
28056 hints.ai_addrlen = static_cast<socklen_t>(
28057 sizeof(addr) - sizeof(addr.sun_path) + addrlen);
28058
28059 fcntl(sock, F_SETFD, FD_CLOEXEC);
28060 if (socket_options) { socket_options(sock); }
28061
28062 if (!bind_or_connect(sock, hints)) {
28063 close_socket(sock);
28064 sock = INVALID_SOCKET;
28065 }
28066 }
28067 return sock;
28068 }
28069#endif
28070
28071 auto service = std::to_string(port);
28072
28073 if (getaddrinfo(node, service.c_str(), &hints, &result)) {
28074#if defined __linux__ && !defined __ANDROID__
28075 res_init();
28076#endif
28077 return INVALID_SOCKET;
28078 }
28079
28080 for (auto rp = result; rp; rp = rp->ai_next) {
28081 // Create a socket
28082#ifdef _WIN32
28083 auto sock =
28084 WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol, nullptr, 0,
28085 WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
28100 if (sock == INVALID_SOCKET) {
28101 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
28102 }
28103#else
28104 auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
28105#endif
28106 if (sock == INVALID_SOCKET) { continue; }
28107
28108#ifndef _WIN32
28109 if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) {
28110 close_socket(sock);
28111 continue;
28112 }
28113#endif
28114
28115 if (tcp_nodelay) {
28116 auto yes = 1;
28117#ifdef _WIN32
28118 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
28119 reinterpret_cast<const char *>(&yes), sizeof(yes));
28120#else
28121 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
28122 reinterpret_cast<const void *>(&yes), sizeof(yes));
28123#endif
28124 }
28125
28126 if (socket_options) { socket_options(sock); }
28127
28128 if (rp->ai_family == AF_INET6) {
28129 auto no = 0;
28130#ifdef _WIN32
28131 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
28132 reinterpret_cast<const char *>(&no), sizeof(no));
28133#else
28134 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
28135 reinterpret_cast<const void *>(&no), sizeof(no));
28136#endif
28137 }
28138
28139 // bind or connect
28140 if (bind_or_connect(sock, *rp)) {
28141 freeaddrinfo(result);
28142 return sock;
28143 }
28144
28145 close_socket(sock);
28146 }
28147
28148 freeaddrinfo(result);
28149 return INVALID_SOCKET;
28150}
28151
28152inline void set_nonblocking(socket_t sock, bool nonblocking) {
28153#ifdef _WIN32
28154 auto flags = nonblocking ? 1UL : 0UL;
28155 ioctlsocket(sock, FIONBIO, &flags);
28156#else
28157 auto flags = fcntl(sock, F_GETFL, 0);
28158 fcntl(sock, F_SETFL,
28159 nonblocking ? (flags | O_NONBLOCK) : (flags & (~O_NONBLOCK)));
28160#endif
28161}
28162
28163inline bool is_connection_error() {
28164#ifdef _WIN32
28165 return WSAGetLastError() != WSAEWOULDBLOCK;
28166#else
28167 return errno != EINPROGRESS;
28168#endif
28169}
28170
28171inline bool bind_ip_address(socket_t sock, const std::string &host) {
28172 struct addrinfo hints;
28173 struct addrinfo *result;
28174
28175 memset(&hints, 0, sizeof(struct addrinfo));
28176 hints.ai_family = AF_UNSPEC;
28177 hints.ai_socktype = SOCK_STREAM;
28178 hints.ai_protocol = 0;
28179
28180 if (getaddrinfo(host.c_str(), "0", &hints, &result)) { return false; }
28181
28182 auto ret = false;
28183 for (auto rp = result; rp; rp = rp->ai_next) {
28184 const auto &ai = *rp;
28185 if (!::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
28186 ret = true;
28187 break;
28188 }
28189 }
28190
28191 freeaddrinfo(result);
28192 return ret;
28193}
28194
28195#if !defined _WIN32 && !defined ANDROID && !defined _AIX && !defined __MVS__
28196#define USE_IF2IP
28197#endif
28198
28199#ifdef USE_IF2IP
28200inline std::string if2ip(int address_family, const std::string &ifn) {
28201 struct ifaddrs *ifap;
28202 getifaddrs(&ifap);
28203 std::string addr_candidate;
28204 for (auto ifa = ifap; ifa; ifa = ifa->ifa_next) {
28205 if (ifa->ifa_addr && ifn == ifa->ifa_name &&
28206 (AF_UNSPEC == address_family ||
28207 ifa->ifa_addr->sa_family == address_family)) {
28208 if (ifa->ifa_addr->sa_family == AF_INET) {
28209 auto sa = reinterpret_cast<struct sockaddr_in *>(ifa->ifa_addr);
28210 char buf[INET_ADDRSTRLEN];
28211 if (inet_ntop(AF_INET, &sa->sin_addr, buf, INET_ADDRSTRLEN)) {
28212 freeifaddrs(ifap);
28213 return std::string(buf, INET_ADDRSTRLEN);
28214 }
28215 } else if (ifa->ifa_addr->sa_family == AF_INET6) {
28216 auto sa = reinterpret_cast<struct sockaddr_in6 *>(ifa->ifa_addr);
28217 if (!IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) {
28218 char buf[INET6_ADDRSTRLEN] = {};
28219 if (inet_ntop(AF_INET6, &sa->sin6_addr, buf, INET6_ADDRSTRLEN)) {
28220 // equivalent to mac's IN6_IS_ADDR_UNIQUE_LOCAL
28221 auto s6_addr_head = sa->sin6_addr.s6_addr[0];
28222 if (s6_addr_head == 0xfc || s6_addr_head == 0xfd) {
28223 addr_candidate = std::string(buf, INET6_ADDRSTRLEN);
28224 } else {
28225 freeifaddrs(ifap);
28226 return std::string(buf, INET6_ADDRSTRLEN);
28227 }
28228 }
28229 }
28230 }
28231 }
28232 }
28233 freeifaddrs(ifap);
28234 return addr_candidate;
28235}
28236#endif
28237
28238inline socket_t create_client_socket(
28239 const std::string &host, const std::string &ip, int port,
28240 int address_family, bool tcp_nodelay, SocketOptions socket_options,
28241 time_t connection_timeout_sec, time_t connection_timeout_usec,
28242 time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
28243 time_t write_timeout_usec, const std::string &intf, Error &error) {
28244 auto sock = create_socket(
28245 host, ip, port, address_family, 0, tcp_nodelay, std::move(socket_options),
28246 [&](socket_t sock2, struct addrinfo &ai) -> bool {
28247 if (!intf.empty()) {
28248#ifdef USE_IF2IP
28249 auto ip_from_if = if2ip(address_family, intf);
28250 if (ip_from_if.empty()) { ip_from_if = intf; }
28251 if (!bind_ip_address(sock2, ip_from_if)) {
28252 error = Error::BindIPAddress;
28253 return false;
28254 }
28255#endif
28256 }
28257
28258 set_nonblocking(sock2, true);
28259
28260 auto ret =
28261 ::connect(sock2, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen));
28262
28263 if (ret < 0) {
28264 if (is_connection_error()) {
28265 error = Error::Connection;
28266 return false;
28267 }
28268 error = wait_until_socket_is_ready(sock2, connection_timeout_sec,
28269 connection_timeout_usec);
28270 if (error != Error::Success) { return false; }
28271 }
28272
28273 set_nonblocking(sock2, false);
28274
28275 {
28276#ifdef _WIN32
28277 auto timeout = static_cast<uint32_t>(read_timeout_sec * 1000 +
28278 read_timeout_usec / 1000);
28279 setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO,
28280 reinterpret_cast<const char *>(&timeout), sizeof(timeout));
28281#else
28282 timeval tv;
28283 tv.tv_sec = static_cast<long>(read_timeout_sec);
28284 tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec);
28285 setsockopt(sock2, SOL_SOCKET, SO_RCVTIMEO,
28286 reinterpret_cast<const void *>(&tv), sizeof(tv));
28287#endif
28288 }
28289 {
28290
28291#ifdef _WIN32
28292 auto timeout = static_cast<uint32_t>(write_timeout_sec * 1000 +
28293 write_timeout_usec / 1000);
28294 setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO,
28295 reinterpret_cast<const char *>(&timeout), sizeof(timeout));
28296#else
28297 timeval tv;
28298 tv.tv_sec = static_cast<long>(write_timeout_sec);
28299 tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec);
28300 setsockopt(sock2, SOL_SOCKET, SO_SNDTIMEO,
28301 reinterpret_cast<const void *>(&tv), sizeof(tv));
28302#endif
28303 }
28304
28305 error = Error::Success;
28306 return true;
28307 });
28308
28309 if (sock != INVALID_SOCKET) {
28310 error = Error::Success;
28311 } else {
28312 if (error == Error::Success) { error = Error::Connection; }
28313 }
28314
28315 return sock;
28316}
28317
28318inline bool get_ip_and_port(const struct sockaddr_storage &addr,
28319 socklen_t addr_len, std::string &ip, int &port) {
28320 if (addr.ss_family == AF_INET) {
28321 port = ntohs(reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_port);
28322 } else if (addr.ss_family == AF_INET6) {
28323 port =
28324 ntohs(reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_port);
28325 } else {
28326 return false;
28327 }
28328
28329 std::array<char, NI_MAXHOST> ipstr{};
28330 if (getnameinfo(reinterpret_cast<const struct sockaddr *>(&addr), addr_len,
28331 ipstr.data(), static_cast<socklen_t>(ipstr.size()), nullptr,
28332 0, NI_NUMERICHOST)) {
28333 return false;
28334 }
28335
28336 ip = ipstr.data();
28337 return true;
28338}
28339
28340inline void get_local_ip_and_port(socket_t sock, std::string &ip, int &port) {
28341 struct sockaddr_storage addr;
28342 socklen_t addr_len = sizeof(addr);
28343 if (!getsockname(sock, reinterpret_cast<struct sockaddr *>(&addr),
28344 &addr_len)) {
28345 get_ip_and_port(addr, addr_len, ip, port);
28346 }
28347}
28348
28349inline void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) {
28350 struct sockaddr_storage addr;
28351 socklen_t addr_len = sizeof(addr);
28352
28353 if (!getpeername(sock, reinterpret_cast<struct sockaddr *>(&addr),
28354 &addr_len)) {
28355#ifndef _WIN32
28356 if (addr.ss_family == AF_UNIX) {
28357#if defined(__linux__)
28358 struct ucred ucred;
28359 socklen_t len = sizeof(ucred);
28360 if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == 0) {
28361 port = ucred.pid;
28362 }
28363#elif defined(SOL_LOCAL) && defined(SO_PEERPID) // __APPLE__
28364 pid_t pid;
28365 socklen_t len = sizeof(pid);
28366 if (getsockopt(sock, SOL_LOCAL, SO_PEERPID, &pid, &len) == 0) {
28367 port = pid;
28368 }
28369#endif
28370 return;
28371 }
28372#endif
28373 get_ip_and_port(addr, addr_len, ip, port);
28374 }
28375}
28376
28377inline constexpr unsigned int str2tag_core(const char *s, size_t l,
28378 unsigned int h) {
28379 return (l == 0)
28380 ? h
28381 : str2tag_core(
28382 s + 1, l - 1,
28383 // Unsets the 6 high bits of h, therefore no overflow happens
28384 (((std::numeric_limits<unsigned int>::max)() >> 6) &
28385 h * 33) ^
28386 static_cast<unsigned char>(*s));
28387}
28388
28389inline unsigned int str2tag(const std::string &s) {
28390 return str2tag_core(s.data(), s.size(), 0);
28391}
28392
28393namespace udl {
28394
28395inline constexpr unsigned int operator"" _t(const char *s, size_t l) {
28396 return str2tag_core(s, l, 0);
28397}
28398
28399} // namespace udl
28400
28401inline std::string
28402find_content_type(const std::string &path,
28403 const std::map<std::string, std::string> &user_data,
28404 const std::string &default_content_type) {
28405 auto ext = file_extension(path);
28406
28407 auto it = user_data.find(ext);
28408 if (it != user_data.end()) { return it->second; }
28409
28410 using udl::operator""_t;
28411
28412 switch (str2tag(ext)) {
28413 default: return default_content_type;
28414
28415 case "css"_t: return "text/css";
28416 case "csv"_t: return "text/csv";
28417 case "htm"_t:
28418 case "html"_t: return "text/html";
28419 case "js"_t:
28420 case "mjs"_t: return "text/javascript";
28421 case "txt"_t: return "text/plain";
28422 case "vtt"_t: return "text/vtt";
28423
28424 case "apng"_t: return "image/apng";
28425 case "avif"_t: return "image/avif";
28426 case "bmp"_t: return "image/bmp";
28427 case "gif"_t: return "image/gif";
28428 case "png"_t: return "image/png";
28429 case "svg"_t: return "image/svg+xml";
28430 case "webp"_t: return "image/webp";
28431 case "ico"_t: return "image/x-icon";
28432 case "tif"_t: return "image/tiff";
28433 case "tiff"_t: return "image/tiff";
28434 case "jpg"_t:
28435 case "jpeg"_t: return "image/jpeg";
28436
28437 case "mp4"_t: return "video/mp4";
28438 case "mpeg"_t: return "video/mpeg";
28439 case "webm"_t: return "video/webm";
28440
28441 case "mp3"_t: return "audio/mp3";
28442 case "mpga"_t: return "audio/mpeg";
28443 case "weba"_t: return "audio/webm";
28444 case "wav"_t: return "audio/wave";
28445
28446 case "otf"_t: return "font/otf";
28447 case "ttf"_t: return "font/ttf";
28448 case "woff"_t: return "font/woff";
28449 case "woff2"_t: return "font/woff2";
28450
28451 case "7z"_t: return "application/x-7z-compressed";
28452 case "atom"_t: return "application/atom+xml";
28453 case "pdf"_t: return "application/pdf";
28454 case "json"_t: return "application/json";
28455 case "rss"_t: return "application/rss+xml";
28456 case "tar"_t: return "application/x-tar";
28457 case "xht"_t:
28458 case "xhtml"_t: return "application/xhtml+xml";
28459 case "xslt"_t: return "application/xslt+xml";
28460 case "xml"_t: return "application/xml";
28461 case "gz"_t: return "application/gzip";
28462 case "zip"_t: return "application/zip";
28463 case "wasm"_t: return "application/wasm";
28464 }
28465}
28466
28467inline bool can_compress_content_type(const std::string &content_type) {
28468 using udl::operator""_t;
28469
28470 auto tag = str2tag(content_type);
28471
28472 switch (tag) {
28473 case "image/svg+xml"_t:
28474 case "application/javascript"_t:
28475 case "application/json"_t:
28476 case "application/xml"_t:
28477 case "application/protobuf"_t:
28478 case "application/xhtml+xml"_t: return true;
28479
28480 default:
28481 return !content_type.rfind("text/", 0) && tag != "text/event-stream"_t;
28482 }
28483}
28484
28485inline EncodingType encoding_type(const Request &req, const Response &res) {
28486 auto ret =
28487 detail::can_compress_content_type(res.get_header_value("Content-Type"));
28488 if (!ret) { return EncodingType::None; }
28489
28490 const auto &s = req.get_header_value("Accept-Encoding");
28491 (void)(s);
28492
28493#ifdef CPPHTTPLIB_BROTLI_SUPPORT
28494 // TODO: 'Accept-Encoding' has br, not br;q=0
28495 ret = s.find("br") != std::string::npos;
28496 if (ret) { return EncodingType::Brotli; }
28497#endif
28498
28499#ifdef CPPHTTPLIB_ZLIB_SUPPORT
28500 // TODO: 'Accept-Encoding' has gzip, not gzip;q=0
28501 ret = s.find("gzip") != std::string::npos;
28502 if (ret) { return EncodingType::Gzip; }
28503#endif
28504
28505 return EncodingType::None;
28506}
28507
28508inline bool nocompressor::compress(const char *data, size_t data_length,
28509 bool /*last*/, Callback callback) {
28510 if (!data_length) { return true; }
28511 return callback(data, data_length);
28512}
28513
28514#ifdef CPPHTTPLIB_ZLIB_SUPPORT
28515inline gzip_compressor::gzip_compressor() {
28516 std::memset(&strm_, 0, sizeof(strm_));
28517 strm_.zalloc = Z_NULL;
28518 strm_.zfree = Z_NULL;
28519 strm_.opaque = Z_NULL;
28520
28521 is_valid_ = deflateInit2(&strm_, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8,
28522 Z_DEFAULT_STRATEGY) == Z_OK;
28523}
28524
28525inline gzip_compressor::~gzip_compressor() { deflateEnd(&strm_); }
28526
28527inline bool gzip_compressor::compress(const char *data, size_t data_length,
28528 bool last, Callback callback) {
28529 assert(is_valid_);
28530
28531 do {
28532 constexpr size_t max_avail_in =
28533 (std::numeric_limits<decltype(strm_.avail_in)>::max)();
28534
28535 strm_.avail_in = static_cast<decltype(strm_.avail_in)>(
28536 (std::min)(data_length, max_avail_in));
28537 strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
28538
28539 data_length -= strm_.avail_in;
28540 data += strm_.avail_in;
28541
28542 auto flush = (last && data_length == 0) ? Z_FINISH : Z_NO_FLUSH;
28543 auto ret = Z_OK;
28544
28545 std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
28546 do {
28547 strm_.avail_out = static_cast<uInt>(buff.size());
28548 strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
28549
28550 ret = deflate(&strm_, flush);
28551 if (ret == Z_STREAM_ERROR) { return false; }
28552
28553 if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
28554 return false;
28555 }
28556 } while (strm_.avail_out == 0);
28557
28558 assert((flush == Z_FINISH && ret == Z_STREAM_END) ||
28559 (flush == Z_NO_FLUSH && ret == Z_OK));
28560 assert(strm_.avail_in == 0);
28561 } while (data_length > 0);
28562
28563 return true;
28564}
28565
28566inline gzip_decompressor::gzip_decompressor() {
28567 std::memset(&strm_, 0, sizeof(strm_));
28568 strm_.zalloc = Z_NULL;
28569 strm_.zfree = Z_NULL;
28570 strm_.opaque = Z_NULL;
28571
28572 // 15 is the value of wbits, which should be at the maximum possible value
28573 // to ensure that any gzip stream can be decoded. The offset of 32 specifies
28574 // that the stream type should be automatically detected either gzip or
28575 // deflate.
28576 is_valid_ = inflateInit2(&strm_, 32 + 15) == Z_OK;
28577}
28578
28579inline gzip_decompressor::~gzip_decompressor() { inflateEnd(&strm_); }
28580
28581inline bool gzip_decompressor::is_valid() const { return is_valid_; }
28582
28583inline bool gzip_decompressor::decompress(const char *data, size_t data_length,
28584 Callback callback) {
28585 assert(is_valid_);
28586
28587 auto ret = Z_OK;
28588
28589 do {
28590 constexpr size_t max_avail_in =
28591 (std::numeric_limits<decltype(strm_.avail_in)>::max)();
28592
28593 strm_.avail_in = static_cast<decltype(strm_.avail_in)>(
28594 (std::min)(data_length, max_avail_in));
28595 strm_.next_in = const_cast<Bytef *>(reinterpret_cast<const Bytef *>(data));
28596
28597 data_length -= strm_.avail_in;
28598 data += strm_.avail_in;
28599
28600 std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
28601 while (strm_.avail_in > 0 && ret == Z_OK) {
28602 strm_.avail_out = static_cast<uInt>(buff.size());
28603 strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
28604
28605 ret = inflate(&strm_, Z_NO_FLUSH);
28606
28607 assert(ret != Z_STREAM_ERROR);
28608 switch (ret) {
28609 case Z_NEED_DICT:
28610 case Z_DATA_ERROR:
28611 case Z_MEM_ERROR: inflateEnd(&strm_); return false;
28612 }
28613
28614 if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
28615 return false;
28616 }
28617 }
28618
28619 if (ret != Z_OK && ret != Z_STREAM_END) { return false; }
28620
28621 } while (data_length > 0);
28622
28623 return true;
28624}
28625#endif
28626
28627#ifdef CPPHTTPLIB_BROTLI_SUPPORT
28628inline brotli_compressor::brotli_compressor() {
28629 state_ = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr);
28630}
28631
28632inline brotli_compressor::~brotli_compressor() {
28633 BrotliEncoderDestroyInstance(state_);
28634}
28635
28636inline bool brotli_compressor::compress(const char *data, size_t data_length,
28637 bool last, Callback callback) {
28638 std::array<uint8_t, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
28639
28640 auto operation = last ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS;
28641 auto available_in = data_length;
28642 auto next_in = reinterpret_cast<const uint8_t *>(data);
28643
28644 for (;;) {
28645 if (last) {
28646 if (BrotliEncoderIsFinished(state_)) { break; }
28647 } else {
28648 if (!available_in) { break; }
28649 }
28650
28651 auto available_out = buff.size();
28652 auto next_out = buff.data();
28653
28654 if (!BrotliEncoderCompressStream(state_, operation, &available_in, &next_in,
28655 &available_out, &next_out, nullptr)) {
28656 return false;
28657 }
28658
28659 auto output_bytes = buff.size() - available_out;
28660 if (output_bytes) {
28661 callback(reinterpret_cast<const char *>(buff.data()), output_bytes);
28662 }
28663 }
28664
28665 return true;
28666}
28667
28668inline brotli_decompressor::brotli_decompressor() {
28669 decoder_s = BrotliDecoderCreateInstance(0, 0, 0);
28670 decoder_r = decoder_s ? BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT
28671 : BROTLI_DECODER_RESULT_ERROR;
28672}
28673
28674inline brotli_decompressor::~brotli_decompressor() {
28675 if (decoder_s) { BrotliDecoderDestroyInstance(decoder_s); }
28676}
28677
28678inline bool brotli_decompressor::is_valid() const { return decoder_s; }
28679
28680inline bool brotli_decompressor::decompress(const char *data,
28681 size_t data_length,
28682 Callback callback) {
28683 if (decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
28684 decoder_r == BROTLI_DECODER_RESULT_ERROR) {
28685 return 0;
28686 }
28687
28688 auto next_in = reinterpret_cast<const uint8_t *>(data);
28689 size_t avail_in = data_length;
28690 size_t total_out;
28691
28692 decoder_r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
28693
28694 std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
28695 while (decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
28696 char *next_out = buff.data();
28697 size_t avail_out = buff.size();
28698
28699 decoder_r = BrotliDecoderDecompressStream(
28700 decoder_s, &avail_in, &next_in, &avail_out,
28701 reinterpret_cast<uint8_t **>(&next_out), &total_out);
28702
28703 if (decoder_r == BROTLI_DECODER_RESULT_ERROR) { return false; }
28704
28705 if (!callback(buff.data(), buff.size() - avail_out)) { return false; }
28706 }
28707
28708 return decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
28709 decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
28710}
28711#endif
28712
28713inline bool has_header(const Headers &headers, const std::string &key) {
28714 return headers.find(key) != headers.end();
28715}
28716
28717inline const char *get_header_value(const Headers &headers,
28718 const std::string &key, size_t id,
28719 const char *def) {
28720 auto rng = headers.equal_range(key);
28721 auto it = rng.first;
28722 std::advance(it, static_cast<ssize_t>(id));
28723 if (it != rng.second) { return it->second.c_str(); }
28724 return def;
28725}
28726
28727inline bool compare_case_ignore(const std::string &a, const std::string &b) {
28728 if (a.size() != b.size()) { return false; }
28729 for (size_t i = 0; i < b.size(); i++) {
28730 if (::tolower(a[i]) != ::tolower(b[i])) { return false; }
28731 }
28732 return true;
28733}
28734
28735template <typename T>
28736inline bool parse_header(const char *beg, const char *end, T fn) {
28737 // Skip trailing spaces and tabs.
28738 while (beg < end && is_space_or_tab(end[-1])) {
28739 end--;
28740 }
28741
28742 auto p = beg;
28743 while (p < end && *p != ':') {
28744 p++;
28745 }
28746
28747 if (p == end) { return false; }
28748
28749 auto key_end = p;
28750
28751 if (*p++ != ':') { return false; }
28752
28753 while (p < end && is_space_or_tab(*p)) {
28754 p++;
28755 }
28756
28757 if (p < end) {
28758 auto key_len = key_end - beg;
28759 if (!key_len) { return false; }
28760
28761 auto key = std::string(beg, key_end);
28762 auto val = compare_case_ignore(key, "Location")
28763 ? std::string(p, end)
28764 : decode_url(std::string(p, end), false);
28765 fn(key, val);
28766 return true;
28767 }
28768
28769 return false;
28770}
28771
28772inline bool read_headers(Stream &strm, Headers &headers) {
28773 const auto bufsiz = 2048;
28774 char buf[bufsiz];
28775 stream_line_reader line_reader(strm, buf, bufsiz);
28776
28777 for (;;) {
28778 if (!line_reader.getline()) { return false; }
28779
28780 // Check if the line ends with CRLF.
28781 auto line_terminator_len = 2;
28782 if (line_reader.end_with_crlf()) {
28783 // Blank line indicates end of headers.
28784 if (line_reader.size() == 2) { break; }
28785#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
28786 } else {
28787 // Blank line indicates end of headers.
28788 if (line_reader.size() == 1) { break; }
28789 line_terminator_len = 1;
28790 }
28791#else
28792 } else {
28793 continue; // Skip invalid line.
28794 }
28795#endif
28796
28797 if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
28798
28799 // Exclude line terminator
28800 auto end = line_reader.ptr() + line_reader.size() - line_terminator_len;
28801
28802 parse_header(line_reader.ptr(), end,
28803 [&](const std::string &key, const std::string &val) {
28804 headers.emplace(key, val);
28805 });
28806 }
28807
28808 return true;
28809}
28810
28811inline bool read_content_with_length(Stream &strm, uint64_t len,
28812 Progress progress,
28813 ContentReceiverWithProgress out) {
28814 char buf[CPPHTTPLIB_RECV_BUFSIZ];
28815
28816 uint64_t r = 0;
28817 while (r < len) {
28818 auto read_len = static_cast<size_t>(len - r);
28819 auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ));
28820 if (n <= 0) { return false; }
28821
28822 if (!out(buf, static_cast<size_t>(n), r, len)) { return false; }
28823 r += static_cast<uint64_t>(n);
28824
28825 if (progress) {
28826 if (!progress(r, len)) { return false; }
28827 }
28828 }
28829
28830 return true;
28831}
28832
28833inline void skip_content_with_length(Stream &strm, uint64_t len) {
28834 char buf[CPPHTTPLIB_RECV_BUFSIZ];
28835 uint64_t r = 0;
28836 while (r < len) {
28837 auto read_len = static_cast<size_t>(len - r);
28838 auto n = strm.read(buf, (std::min)(read_len, CPPHTTPLIB_RECV_BUFSIZ));
28839 if (n <= 0) { return; }
28840 r += static_cast<uint64_t>(n);
28841 }
28842}
28843
28844inline bool read_content_without_length(Stream &strm,
28845 ContentReceiverWithProgress out) {
28846 char buf[CPPHTTPLIB_RECV_BUFSIZ];
28847 uint64_t r = 0;
28848 for (;;) {
28849 auto n = strm.read(buf, CPPHTTPLIB_RECV_BUFSIZ);
28850 if (n <= 0) { return true; }
28851
28852 if (!out(buf, static_cast<size_t>(n), r, 0)) { return false; }
28853 r += static_cast<uint64_t>(n);
28854 }
28855
28856 return true;
28857}
28858
28859template <typename T>
28860inline bool read_content_chunked(Stream &strm, T &x,
28861 ContentReceiverWithProgress out) {
28862 const auto bufsiz = 16;
28863 char buf[bufsiz];
28864
28865 stream_line_reader line_reader(strm, buf, bufsiz);
28866
28867 if (!line_reader.getline()) { return false; }
28868
28869 unsigned long chunk_len;
28870 while (true) {
28871 char *end_ptr;
28872
28873 chunk_len = std::strtoul(line_reader.ptr(), &end_ptr, 16);
28874
28875 if (end_ptr == line_reader.ptr()) { return false; }
28876 if (chunk_len == ULONG_MAX) { return false; }
28877
28878 if (chunk_len == 0) { break; }
28879
28880 if (!read_content_with_length(strm, chunk_len, nullptr, out)) {
28881 return false;
28882 }
28883
28884 if (!line_reader.getline()) { return false; }
28885
28886 if (strcmp(line_reader.ptr(), "\r\n") != 0) { return false; }
28887
28888 if (!line_reader.getline()) { return false; }
28889 }
28890
28891 assert(chunk_len == 0);
28892
28893 // Trailer
28894 if (!line_reader.getline()) { return false; }
28895
28896 while (strcmp(line_reader.ptr(), "\r\n") != 0) {
28897 if (line_reader.size() > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
28898
28899 // Exclude line terminator
28900 constexpr auto line_terminator_len = 2;
28901 auto end = line_reader.ptr() + line_reader.size() - line_terminator_len;
28902
28903 parse_header(line_reader.ptr(), end,
28904 [&](const std::string &key, const std::string &val) {
28905 x.headers.emplace(key, val);
28906 });
28907
28908 if (!line_reader.getline()) { return false; }
28909 }
28910
28911 return true;
28912}
28913
28914inline bool is_chunked_transfer_encoding(const Headers &headers) {
28915 return compare_case_ignore(
28916 get_header_value(headers, "Transfer-Encoding", 0, ""), "chunked");
28917}
28918
28919template <typename T, typename U>
28920bool prepare_content_receiver(T &x, int &status,
28921 ContentReceiverWithProgress receiver,
28922 bool decompress, U callback) {
28923 if (decompress) {
28924 std::string encoding = x.get_header_value("Content-Encoding");
28925 std::unique_ptr<decompressor> decompressor;
28926
28927 if (encoding == "gzip" || encoding == "deflate") {
28928#ifdef CPPHTTPLIB_ZLIB_SUPPORT
28929 decompressor = detail::make_unique<gzip_decompressor>();
28930#else
28931 status = StatusCode::UnsupportedMediaType_415;
28932 return false;
28933#endif
28934 } else if (encoding.find("br") != std::string::npos) {
28935#ifdef CPPHTTPLIB_BROTLI_SUPPORT
28936 decompressor = detail::make_unique<brotli_decompressor>();
28937#else
28938 status = StatusCode::UnsupportedMediaType_415;
28939 return false;
28940#endif
28941 }
28942
28943 if (decompressor) {
28944 if (decompressor->is_valid()) {
28945 ContentReceiverWithProgress out = [&](const char *buf, size_t n,
28946 uint64_t off, uint64_t len) {
28947 return decompressor->decompress(buf, n,
28948 [&](const char *buf2, size_t n2) {
28949 return receiver(buf2, n2, off, len);
28950 });
28951 };
28952 return callback(std::move(out));
28953 } else {
28954 status = StatusCode::InternalServerError_500;
28955 return false;
28956 }
28957 }
28958 }
28959
28960 ContentReceiverWithProgress out = [&](const char *buf, size_t n, uint64_t off,
28961 uint64_t len) {
28962 return receiver(buf, n, off, len);
28963 };
28964 return callback(std::move(out));
28965}
28966
28967template <typename T>
28968bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status,
28969 Progress progress, ContentReceiverWithProgress receiver,
28970 bool decompress) {
28971 return prepare_content_receiver(
28972 x, status, std::move(receiver), decompress,
28973 [&](const ContentReceiverWithProgress &out) {
28974 auto ret = true;
28975 auto exceed_payload_max_length = false;
28976
28977 if (is_chunked_transfer_encoding(x.headers)) {
28978 ret = read_content_chunked(strm, x, out);
28979 } else if (!has_header(x.headers, "Content-Length")) {
28980 ret = read_content_without_length(strm, out);
28981 } else {
28982 auto len = get_header_value_u64(x.headers, "Content-Length", 0, 0);
28983 if (len > payload_max_length) {
28984 exceed_payload_max_length = true;
28985 skip_content_with_length(strm, len);
28986 ret = false;
28987 } else if (len > 0) {
28988 ret = read_content_with_length(strm, len, std::move(progress), out);
28989 }
28990 }
28991
28992 if (!ret) {
28993 status = exceed_payload_max_length ? StatusCode::PayloadTooLarge_413
28994 : StatusCode::BadRequest_400;
28995 }
28996 return ret;
28997 });
28998} // namespace detail
28999
29000inline ssize_t write_headers(Stream &strm, const Headers &headers) {
29001 ssize_t write_len = 0;
29002 for (const auto &x : headers) {
29003 auto len =
29004 strm.write_format("%s: %s\r\n", x.first.c_str(), x.second.c_str());
29005 if (len < 0) { return len; }
29006 write_len += len;
29007 }
29008 auto len = strm.write("\r\n");
29009 if (len < 0) { return len; }
29010 write_len += len;
29011 return write_len;
29012}
29013
29014inline bool write_data(Stream &strm, const char *d, size_t l) {
29015 size_t offset = 0;
29016 while (offset < l) {
29017 auto length = strm.write(d + offset, l - offset);
29018 if (length < 0) { return false; }
29019 offset += static_cast<size_t>(length);
29020 }
29021 return true;
29022}
29023
29024template <typename T>
29025inline bool write_content(Stream &strm, const ContentProvider &content_provider,
29026 size_t offset, size_t length, T is_shutting_down,
29027 Error &error) {
29028 size_t end_offset = offset + length;
29029 auto ok = true;
29030 DataSink data_sink;
29031
29032 data_sink.write = [&](const char *d, size_t l) -> bool {
29033 if (ok) {
29034 if (strm.is_writable() && write_data(strm, d, l)) {
29035 offset += l;
29036 } else {
29037 ok = false;
29038 }
29039 }
29040 return ok;
29041 };
29042
29043 data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
29044
29045 while (offset < end_offset && !is_shutting_down()) {
29046 if (!strm.is_writable()) {
29047 error = Error::Write;
29048 return false;
29049 } else if (!content_provider(offset, end_offset - offset, data_sink)) {
29050 error = Error::Canceled;
29051 return false;
29052 } else if (!ok) {
29053 error = Error::Write;
29054 return false;
29055 }
29056 }
29057
29058 error = Error::Success;
29059 return true;
29060}
29061
29062template <typename T>
29063inline bool write_content(Stream &strm, const ContentProvider &content_provider,
29064 size_t offset, size_t length,
29065 const T &is_shutting_down) {
29066 auto error = Error::Success;
29067 return write_content(strm, content_provider, offset, length, is_shutting_down,
29068 error);
29069}
29070
29071template <typename T>
29072inline bool
29073write_content_without_length(Stream &strm,
29074 const ContentProvider &content_provider,
29075 const T &is_shutting_down) {
29076 size_t offset = 0;
29077 auto data_available = true;
29078 auto ok = true;
29079 DataSink data_sink;
29080
29081 data_sink.write = [&](const char *d, size_t l) -> bool {
29082 if (ok) {
29083 offset += l;
29084 if (!strm.is_writable() || !write_data(strm, d, l)) { ok = false; }
29085 }
29086 return ok;
29087 };
29088
29089 data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
29090
29091 data_sink.done = [&](void) { data_available = false; };
29092
29093 while (data_available && !is_shutting_down()) {
29094 if (!strm.is_writable()) {
29095 return false;
29096 } else if (!content_provider(offset, 0, data_sink)) {
29097 return false;
29098 } else if (!ok) {
29099 return false;
29100 }
29101 }
29102 return true;
29103}
29104
29105template <typename T, typename U>
29106inline bool
29107write_content_chunked(Stream &strm, const ContentProvider &content_provider,
29108 const T &is_shutting_down, U &compressor, Error &error) {
29109 size_t offset = 0;
29110 auto data_available = true;
29111 auto ok = true;
29112 DataSink data_sink;
29113
29114 data_sink.write = [&](const char *d, size_t l) -> bool {
29115 if (ok) {
29116 data_available = l > 0;
29117 offset += l;
29118
29119 std::string payload;
29120 if (compressor.compress(d, l, false,
29121 [&](const char *data, size_t data_len) {
29122 payload.append(data, data_len);
29123 return true;
29124 })) {
29125 if (!payload.empty()) {
29126 // Emit chunked response header and footer for each chunk
29127 auto chunk =
29128 from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
29129 if (!strm.is_writable() ||
29130 !write_data(strm, chunk.data(), chunk.size())) {
29131 ok = false;
29132 }
29133 }
29134 } else {
29135 ok = false;
29136 }
29137 }
29138 return ok;
29139 };
29140
29141 data_sink.is_writable = [&]() -> bool { return strm.is_writable(); };
29142
29143 auto done_with_trailer = [&](const Headers *trailer) {
29144 if (!ok) { return; }
29145
29146 data_available = false;
29147
29148 std::string payload;
29149 if (!compressor.compress(nullptr, 0, true,
29150 [&](const char *data, size_t data_len) {
29151 payload.append(data, data_len);
29152 return true;
29153 })) {
29154 ok = false;
29155 return;
29156 }
29157
29158 if (!payload.empty()) {
29159 // Emit chunked response header and footer for each chunk
29160 auto chunk = from_i_to_hex(payload.size()) + "\r\n" + payload + "\r\n";
29161 if (!strm.is_writable() ||
29162 !write_data(strm, chunk.data(), chunk.size())) {
29163 ok = false;
29164 return;
29165 }
29166 }
29167
29168 static const std::string done_marker("0\r\n");
29169 if (!write_data(strm, done_marker.data(), done_marker.size())) {
29170 ok = false;
29171 }
29172
29173 // Trailer
29174 if (trailer) {
29175 for (const auto &kv : *trailer) {
29176 std::string field_line = kv.first + ": " + kv.second + "\r\n";
29177 if (!write_data(strm, field_line.data(), field_line.size())) {
29178 ok = false;
29179 }
29180 }
29181 }
29182
29183 static const std::string crlf("\r\n");
29184 if (!write_data(strm, crlf.data(), crlf.size())) { ok = false; }
29185 };
29186
29187 data_sink.done = [&](void) { done_with_trailer(nullptr); };
29188
29189 data_sink.done_with_trailer = [&](const Headers &trailer) {
29190 done_with_trailer(&trailer);
29191 };
29192
29193 while (data_available && !is_shutting_down()) {
29194 if (!strm.is_writable()) {
29195 error = Error::Write;
29196 return false;
29197 } else if (!content_provider(offset, 0, data_sink)) {
29198 error = Error::Canceled;
29199 return false;
29200 } else if (!ok) {
29201 error = Error::Write;
29202 return false;
29203 }
29204 }
29205
29206 error = Error::Success;
29207 return true;
29208}
29209
29210template <typename T, typename U>
29211inline bool write_content_chunked(Stream &strm,
29212 const ContentProvider &content_provider,
29213 const T &is_shutting_down, U &compressor) {
29214 auto error = Error::Success;
29215 return write_content_chunked(strm, content_provider, is_shutting_down,
29216 compressor, error);
29217}
29218
29219template <typename T>
29220inline bool redirect(T &cli, Request &req, Response &res,
29221 const std::string &path, const std::string &location,
29222 Error &error) {
29223 Request new_req = req;
29224 new_req.path = path;
29225 new_req.redirect_count_ -= 1;
29226
29227 if (res.status == StatusCode::SeeOther_303 &&
29228 (req.method != "GET" && req.method != "HEAD")) {
29229 new_req.method = "GET";
29230 new_req.body.clear();
29231 new_req.headers.clear();
29232 }
29233
29234 Response new_res;
29235
29236 auto ret = cli.send(new_req, new_res, error);
29237 if (ret) {
29238 req = new_req;
29239 res = new_res;
29240
29241 if (res.location.empty()) { res.location = location; }
29242 }
29243 return ret;
29244}
29245
29246inline std::string params_to_query_str(const Params &params) {
29247 std::string query;
29248
29249 for (auto it = params.begin(); it != params.end(); ++it) {
29250 if (it != params.begin()) { query += "&"; }
29251 query += it->first;
29252 query += "=";
29253 query += encode_query_param(it->second);
29254 }
29255 return query;
29256}
29257
29258inline void parse_query_text(const char *data, std::size_t size,
29259 Params &params) {
29260 std::set<std::string> cache;
29261 split(data, data + size, '&', [&](const char *b, const char *e) {
29262 std::string kv(b, e);
29263 if (cache.find(kv) != cache.end()) { return; }
29264 cache.insert(std::move(kv));
29265
29266 std::string key;
29267 std::string val;
29268 divide(b, static_cast<std::size_t>(e - b), '=',
29269 [&](const char *lhs_data, std::size_t lhs_size, const char *rhs_data,
29270 std::size_t rhs_size) {
29271 key.assign(lhs_data, lhs_size);
29272 val.assign(rhs_data, rhs_size);
29273 });
29274
29275 if (!key.empty()) {
29276 params.emplace(decode_url(key, true), decode_url(val, true));
29277 }
29278 });
29279}
29280
29281inline void parse_query_text(const std::string &s, Params &params) {
29282 parse_query_text(s.data(), s.size(), params);
29283}
29284
29285inline bool parse_multipart_boundary(const std::string &content_type,
29286 std::string &boundary) {
29287 auto boundary_keyword = "boundary=";
29288 auto pos = content_type.find(boundary_keyword);
29289 if (pos == std::string::npos) { return false; }
29290 auto end = content_type.find(';', pos);
29291 auto beg = pos + strlen(boundary_keyword);
29292 boundary = trim_double_quotes_copy(content_type.substr(beg, end - beg));
29293 return !boundary.empty();
29294}
29295
29296inline void parse_disposition_params(const std::string &s, Params &params) {
29297 std::set<std::string> cache;
29298 split(s.data(), s.data() + s.size(), ';', [&](const char *b, const char *e) {
29299 std::string kv(b, e);
29300 if (cache.find(kv) != cache.end()) { return; }
29301 cache.insert(kv);
29302
29303 std::string key;
29304 std::string val;
29305 split(b, e, '=', [&](const char *b2, const char *e2) {
29306 if (key.empty()) {
29307 key.assign(b2, e2);
29308 } else {
29309 val.assign(b2, e2);
29310 }
29311 });
29312
29313 if (!key.empty()) {
29314 params.emplace(trim_double_quotes_copy((key)),
29315 trim_double_quotes_copy((val)));
29316 }
29317 });
29318}
29319
29320#ifdef CPPHTTPLIB_NO_EXCEPTIONS
29321inline bool parse_range_header(const std::string &s, Ranges &ranges) {
29322#else
29323inline bool parse_range_header(const std::string &s, Ranges &ranges) try {
29324#endif
29325 auto is_valid = [](const std::string &str) {
29326 return std::all_of(str.cbegin(), str.cend(),
29327 [](unsigned char c) { return std::isdigit(c); });
29328 };
29329
29330 if (s.size() > 7 && s.compare(0, 6, "bytes=") == 0) {
29331 const auto pos = static_cast<size_t>(6);
29332 const auto len = static_cast<size_t>(s.size() - 6);
29333 auto all_valid_ranges = true;
29334 split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) {
29335 if (!all_valid_ranges) { return; }
29336
29337 const auto it = std::find(b, e, '-');
29338 if (it == e) {
29339 all_valid_ranges = false;
29340 return;
29341 }
29342
29343 const auto lhs = std::string(b, it);
29344 const auto rhs = std::string(it + 1, e);
29345 if (!is_valid(lhs) || !is_valid(rhs)) {
29346 all_valid_ranges = false;
29347 return;
29348 }
29349
29350 const auto first =
29351 static_cast<ssize_t>(lhs.empty() ? -1 : std::stoll(lhs));
29352 const auto last =
29353 static_cast<ssize_t>(rhs.empty() ? -1 : std::stoll(rhs));
29354 if ((first == -1 && last == -1) ||
29355 (first != -1 && last != -1 && first > last)) {
29356 all_valid_ranges = false;
29357 return;
29358 }
29359
29360 ranges.emplace_back(first, last);
29361 });
29362 return all_valid_ranges && !ranges.empty();
29363 }
29364 return false;
29365#ifdef CPPHTTPLIB_NO_EXCEPTIONS
29366}
29367#else
29368} catch (...) { return false; }
29369#endif
29370
29372public:
29373 MultipartFormDataParser() = default;
29374
29375 void set_boundary(std::string &&boundary) {
29376 boundary_ = boundary;
29377 dash_boundary_crlf_ = dash_ + boundary_ + crlf_;
29378 crlf_dash_boundary_ = crlf_ + dash_ + boundary_;
29379 }
29380
29381 bool is_valid() const { return is_valid_; }
29382
29383 bool parse(const char *buf, size_t n, const ContentReceiver &content_callback,
29384 const MultipartContentHeader &header_callback) {
29385
29386 buf_append(buf, n);
29387
29388 while (buf_size() > 0) {
29389 switch (state_) {
29390 case 0: { // Initial boundary
29391 buf_erase(buf_find(dash_boundary_crlf_));
29392 if (dash_boundary_crlf_.size() > buf_size()) { return true; }
29393 if (!buf_start_with(dash_boundary_crlf_)) { return false; }
29394 buf_erase(dash_boundary_crlf_.size());
29395 state_ = 1;
29396 break;
29397 }
29398 case 1: { // New entry
29399 clear_file_info();
29400 state_ = 2;
29401 break;
29402 }
29403 case 2: { // Headers
29404 auto pos = buf_find(crlf_);
29405 if (pos > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; }
29406 while (pos < buf_size()) {
29407 // Empty line
29408 if (pos == 0) {
29409 if (!header_callback(file_)) {
29410 is_valid_ = false;
29411 return false;
29412 }
29413 buf_erase(crlf_.size());
29414 state_ = 3;
29415 break;
29416 }
29417
29418 const auto header = buf_head(pos);
29419
29420 if (!parse_header(header.data(), header.data() + header.size(),
29421 [&](const std::string &, const std::string &) {})) {
29422 is_valid_ = false;
29423 return false;
29424 }
29425
29426 static const std::string header_content_type = "Content-Type:";
29427
29428 if (start_with_case_ignore(header, header_content_type)) {
29429 file_.content_type =
29430 trim_copy(header.substr(header_content_type.size()));
29431 } else {
29432 static const std::regex re_content_disposition(
29433 R"~(^Content-Disposition:\s*form-data;\s*(.*)$)~",
29434 std::regex_constants::icase);
29435
29436 std::smatch m;
29437 if (std::regex_match(header, m, re_content_disposition)) {
29438 Params params;
29439 parse_disposition_params(m[1], params);
29440
29441 auto it = params.find("name");
29442 if (it != params.end()) {
29443 file_.name = it->second;
29444 } else {
29445 is_valid_ = false;
29446 return false;
29447 }
29448
29449 it = params.find("filename");
29450 if (it != params.end()) { file_.filename = it->second; }
29451
29452 it = params.find("filename*");
29453 if (it != params.end()) {
29454 // Only allow UTF-8 enconnding...
29455 static const std::regex re_rfc5987_encoding(
29456 R"~(^UTF-8''(.+?)$)~", std::regex_constants::icase);
29457
29458 std::smatch m2;
29459 if (std::regex_match(it->second, m2, re_rfc5987_encoding)) {
29460 file_.filename = decode_url(m2[1], false); // override...
29461 } else {
29462 is_valid_ = false;
29463 return false;
29464 }
29465 }
29466 }
29467 }
29468 buf_erase(pos + crlf_.size());
29469 pos = buf_find(crlf_);
29470 }
29471 if (state_ != 3) { return true; }
29472 break;
29473 }
29474 case 3: { // Body
29475 if (crlf_dash_boundary_.size() > buf_size()) { return true; }
29476 auto pos = buf_find(crlf_dash_boundary_);
29477 if (pos < buf_size()) {
29478 if (!content_callback(buf_data(), pos)) {
29479 is_valid_ = false;
29480 return false;
29481 }
29482 buf_erase(pos + crlf_dash_boundary_.size());
29483 state_ = 4;
29484 } else {
29485 auto len = buf_size() - crlf_dash_boundary_.size();
29486 if (len > 0) {
29487 if (!content_callback(buf_data(), len)) {
29488 is_valid_ = false;
29489 return false;
29490 }
29491 buf_erase(len);
29492 }
29493 return true;
29494 }
29495 break;
29496 }
29497 case 4: { // Boundary
29498 if (crlf_.size() > buf_size()) { return true; }
29499 if (buf_start_with(crlf_)) {
29500 buf_erase(crlf_.size());
29501 state_ = 1;
29502 } else {
29503 if (dash_.size() > buf_size()) { return true; }
29504 if (buf_start_with(dash_)) {
29505 buf_erase(dash_.size());
29506 is_valid_ = true;
29507 buf_erase(buf_size()); // Remove epilogue
29508 } else {
29509 return true;
29510 }
29511 }
29512 break;
29513 }
29514 }
29515 }
29516
29517 return true;
29518 }
29519
29520private:
29521 void clear_file_info() {
29522 file_.name.clear();
29523 file_.filename.clear();
29524 file_.content_type.clear();
29525 }
29526
29527 bool start_with_case_ignore(const std::string &a,
29528 const std::string &b) const {
29529 if (a.size() < b.size()) { return false; }
29530 for (size_t i = 0; i < b.size(); i++) {
29531 if (::tolower(a[i]) != ::tolower(b[i])) { return false; }
29532 }
29533 return true;
29534 }
29535
29536 const std::string dash_ = "--";
29537 const std::string crlf_ = "\r\n";
29538 std::string boundary_;
29539 std::string dash_boundary_crlf_;
29540 std::string crlf_dash_boundary_;
29541
29542 size_t state_ = 0;
29543 bool is_valid_ = false;
29544 MultipartFormData file_;
29545
29546 // Buffer
29547 bool start_with(const std::string &a, size_t spos, size_t epos,
29548 const std::string &b) const {
29549 if (epos - spos < b.size()) { return false; }
29550 for (size_t i = 0; i < b.size(); i++) {
29551 if (a[i + spos] != b[i]) { return false; }
29552 }
29553 return true;
29554 }
29555
29556 size_t buf_size() const { return buf_epos_ - buf_spos_; }
29557
29558 const char *buf_data() const { return &buf_[buf_spos_]; }
29559
29560 std::string buf_head(size_t l) const { return buf_.substr(buf_spos_, l); }
29561
29562 bool buf_start_with(const std::string &s) const {
29563 return start_with(buf_, buf_spos_, buf_epos_, s);
29564 }
29565
29566 size_t buf_find(const std::string &s) const {
29567 auto c = s.front();
29568
29569 size_t off = buf_spos_;
29570 while (off < buf_epos_) {
29571 auto pos = off;
29572 while (true) {
29573 if (pos == buf_epos_) { return buf_size(); }
29574 if (buf_[pos] == c) { break; }
29575 pos++;
29576 }
29577
29578 auto remaining_size = buf_epos_ - pos;
29579 if (s.size() > remaining_size) { return buf_size(); }
29580
29581 if (start_with(buf_, pos, buf_epos_, s)) { return pos - buf_spos_; }
29582
29583 off = pos + 1;
29584 }
29585
29586 return buf_size();
29587 }
29588
29589 void buf_append(const char *data, size_t n) {
29590 auto remaining_size = buf_size();
29591 if (remaining_size > 0 && buf_spos_ > 0) {
29592 for (size_t i = 0; i < remaining_size; i++) {
29593 buf_[i] = buf_[buf_spos_ + i];
29594 }
29595 }
29596 buf_spos_ = 0;
29597 buf_epos_ = remaining_size;
29598
29599 if (remaining_size + n > buf_.size()) { buf_.resize(remaining_size + n); }
29600
29601 for (size_t i = 0; i < n; i++) {
29602 buf_[buf_epos_ + i] = data[i];
29603 }
29604 buf_epos_ += n;
29605 }
29606
29607 void buf_erase(size_t size) { buf_spos_ += size; }
29608
29609 std::string buf_;
29610 size_t buf_spos_ = 0;
29611 size_t buf_epos_ = 0;
29612};
29613
29614inline std::string to_lower(const char *beg, const char *end) {
29615 std::string out;
29616 auto it = beg;
29617 while (it != end) {
29618 out += static_cast<char>(::tolower(*it));
29619 it++;
29620 }
29621 return out;
29622}
29623
29624inline std::string random_string(size_t length) {
29625 static const char data[] =
29626 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
29627
29628 // std::random_device might actually be deterministic on some
29629 // platforms, but due to lack of support in the c++ standard library,
29630 // doing better requires either some ugly hacks or breaking portability.
29631 static std::random_device seed_gen;
29632
29633 // Request 128 bits of entropy for initialization
29634 static std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(),
29635 seed_gen()};
29636
29637 static std::mt19937 engine(seed_sequence);
29638
29639 std::string result;
29640 for (size_t i = 0; i < length; i++) {
29641 result += data[engine() % (sizeof(data) - 1)];
29642 }
29643 return result;
29644}
29645
29646inline std::string make_multipart_data_boundary() {
29647 return "--cpp-httplib-multipart-data-" + detail::random_string(16);
29648}
29649
29650inline bool is_multipart_boundary_chars_valid(const std::string &boundary) {
29651 auto valid = true;
29652 for (size_t i = 0; i < boundary.size(); i++) {
29653 auto c = boundary[i];
29654 if (!std::isalnum(c) && c != '-' && c != '_') {
29655 valid = false;
29656 break;
29657 }
29658 }
29659 return valid;
29660}
29661
29662template <typename T>
29663inline std::string
29664serialize_multipart_formdata_item_begin(const T &item,
29665 const std::string &boundary) {
29666 std::string body = "--" + boundary + "\r\n";
29667 body += "Content-Disposition: form-data; name=\"" + item.name + "\"";
29668 if (!item.filename.empty()) {
29669 body += "; filename=\"" + item.filename + "\"";
29670 }
29671 body += "\r\n";
29672 if (!item.content_type.empty()) {
29673 body += "Content-Type: " + item.content_type + "\r\n";
29674 }
29675 body += "\r\n";
29676
29677 return body;
29678}
29679
29680inline std::string serialize_multipart_formdata_item_end() { return "\r\n"; }
29681
29682inline std::string
29683serialize_multipart_formdata_finish(const std::string &boundary) {
29684 return "--" + boundary + "--\r\n";
29685}
29686
29687inline std::string
29688serialize_multipart_formdata_get_content_type(const std::string &boundary) {
29689 return "multipart/form-data; boundary=" + boundary;
29690}
29691
29692inline std::string
29693serialize_multipart_formdata(const MultipartFormDataItems &items,
29694 const std::string &boundary, bool finish = true) {
29695 std::string body;
29696
29697 for (const auto &item : items) {
29698 body += serialize_multipart_formdata_item_begin(item, boundary);
29699 body += item.content + serialize_multipart_formdata_item_end();
29700 }
29701
29702 if (finish) { body += serialize_multipart_formdata_finish(boundary); }
29703
29704 return body;
29705}
29706
29707inline bool range_error(Request &req, Response &res) {
29708 if (!req.ranges.empty() && 200 <= res.status && res.status < 300) {
29709 ssize_t contant_len = static_cast<ssize_t>(
29710 res.content_length_ ? res.content_length_ : res.body.size());
29711
29712 ssize_t prev_first_pos = -1;
29713 ssize_t prev_last_pos = -1;
29714 size_t overwrapping_count = 0;
29715
29716 // NOTE: The following Range check is based on '14.2. Range' in RFC 9110
29717 // 'HTTP Semantics' to avoid potential denial-of-service attacks.
29718 // https://www.rfc-editor.org/rfc/rfc9110#section-14.2
29719
29720 // Too many ranges
29721 if (req.ranges.size() > CPPHTTPLIB_RANGE_MAX_COUNT) { return true; }
29722
29723 for (auto &r : req.ranges) {
29724 auto &first_pos = r.first;
29725 auto &last_pos = r.second;
29726
29727 if (first_pos == -1 && last_pos == -1) {
29728 first_pos = 0;
29729 last_pos = contant_len;
29730 }
29731
29732 if (first_pos == -1) {
29733 first_pos = contant_len - last_pos;
29734 last_pos = contant_len - 1;
29735 }
29736
29737 if (last_pos == -1) { last_pos = contant_len - 1; }
29738
29739 // Range must be within content length
29740 if (!(0 <= first_pos && first_pos <= last_pos &&
29741 last_pos <= contant_len - 1)) {
29742 return true;
29743 }
29744
29745 // Ranges must be in ascending order
29746 if (first_pos <= prev_first_pos) { return true; }
29747
29748 // Request must not have more than two overlapping ranges
29749 if (first_pos <= prev_last_pos) {
29750 overwrapping_count++;
29751 if (overwrapping_count > 2) { return true; }
29752 }
29753
29754 prev_first_pos = (std::max)(prev_first_pos, first_pos);
29755 prev_last_pos = (std::max)(prev_last_pos, last_pos);
29756 }
29757 }
29758
29759 return false;
29760}
29761
29762inline std::pair<size_t, size_t>
29763get_range_offset_and_length(Range r, size_t content_length) {
29764 assert(r.first != -1 && r.second != -1);
29765 assert(0 <= r.first && r.first < static_cast<ssize_t>(content_length));
29766 assert(r.first <= r.second &&
29767 r.second < static_cast<ssize_t>(content_length));
29768
29769 return std::make_pair(r.first, static_cast<size_t>(r.second - r.first) + 1);
29770}
29771
29772inline std::string make_content_range_header_field(
29773 const std::pair<size_t, size_t> &offset_and_length, size_t content_length) {
29774 auto st = offset_and_length.first;
29775 auto ed = st + offset_and_length.second - 1;
29776
29777 std::string field = "bytes ";
29778 field += std::to_string(st);
29779 field += "-";
29780 field += std::to_string(ed);
29781 field += "/";
29782 field += std::to_string(content_length);
29783 return field;
29784}
29785
29786template <typename SToken, typename CToken, typename Content>
29787bool process_multipart_ranges_data(const Request &req,
29788 const std::string &boundary,
29789 const std::string &content_type,
29790 size_t content_length, SToken stoken,
29791 CToken ctoken, Content content) {
29792 for (size_t i = 0; i < req.ranges.size(); i++) {
29793 ctoken("--");
29794 stoken(boundary);
29795 ctoken("\r\n");
29796 if (!content_type.empty()) {
29797 ctoken("Content-Type: ");
29798 stoken(content_type);
29799 ctoken("\r\n");
29800 }
29801
29802 auto offset_and_length =
29803 get_range_offset_and_length(req.ranges[i], content_length);
29804
29805 ctoken("Content-Range: ");
29806 stoken(make_content_range_header_field(offset_and_length, content_length));
29807 ctoken("\r\n");
29808 ctoken("\r\n");
29809
29810 if (!content(offset_and_length.first, offset_and_length.second)) {
29811 return false;
29812 }
29813 ctoken("\r\n");
29814 }
29815
29816 ctoken("--");
29817 stoken(boundary);
29818 ctoken("--");
29819
29820 return true;
29821}
29822
29823inline void make_multipart_ranges_data(const Request &req, Response &res,
29824 const std::string &boundary,
29825 const std::string &content_type,
29826 size_t content_length,
29827 std::string &data) {
29828 process_multipart_ranges_data(
29829 req, boundary, content_type, content_length,
29830 [&](const std::string &token) { data += token; },
29831 [&](const std::string &token) { data += token; },
29832 [&](size_t offset, size_t length) {
29833 assert(offset + length <= content_length);
29834 data += res.body.substr(offset, length);
29835 return true;
29836 });
29837}
29838
29839inline size_t get_multipart_ranges_data_length(const Request &req,
29840 const std::string &boundary,
29841 const std::string &content_type,
29842 size_t content_length) {
29843 size_t data_length = 0;
29844
29845 process_multipart_ranges_data(
29846 req, boundary, content_type, content_length,
29847 [&](const std::string &token) { data_length += token.size(); },
29848 [&](const std::string &token) { data_length += token.size(); },
29849 [&](size_t /*offset*/, size_t length) {
29850 data_length += length;
29851 return true;
29852 });
29853
29854 return data_length;
29855}
29856
29857template <typename T>
29858inline bool
29859write_multipart_ranges_data(Stream &strm, const Request &req, Response &res,
29860 const std::string &boundary,
29861 const std::string &content_type,
29862 size_t content_length, const T &is_shutting_down) {
29863 return process_multipart_ranges_data(
29864 req, boundary, content_type, content_length,
29865 [&](const std::string &token) { strm.write(token); },
29866 [&](const std::string &token) { strm.write(token); },
29867 [&](size_t offset, size_t length) {
29868 return write_content(strm, res.content_provider_, offset, length,
29869 is_shutting_down);
29870 });
29871}
29872
29873inline bool expect_content(const Request &req) {
29874 if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH" ||
29875 req.method == "PRI" || req.method == "DELETE") {
29876 return true;
29877 }
29878 // TODO: check if Content-Length is set
29879 return false;
29880}
29881
29882inline bool has_crlf(const std::string &s) {
29883 auto p = s.c_str();
29884 while (*p) {
29885 if (*p == '\r' || *p == '\n') { return true; }
29886 p++;
29887 }
29888 return false;
29889}
29890
29891#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
29892inline std::string message_digest(const std::string &s, const EVP_MD *algo) {
29893 auto context = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>(
29894 EVP_MD_CTX_new(), EVP_MD_CTX_free);
29895
29896 unsigned int hash_length = 0;
29897 unsigned char hash[EVP_MAX_MD_SIZE];
29898
29899 EVP_DigestInit_ex(context.get(), algo, nullptr);
29900 EVP_DigestUpdate(context.get(), s.c_str(), s.size());
29901 EVP_DigestFinal_ex(context.get(), hash, &hash_length);
29902
29903 std::stringstream ss;
29904 for (auto i = 0u; i < hash_length; ++i) {
29905 ss << std::hex << std::setw(2) << std::setfill('0')
29906 << static_cast<unsigned int>(hash[i]);
29907 }
29908
29909 return ss.str();
29910}
29911
29912inline std::string MD5(const std::string &s) {
29913 return message_digest(s, EVP_md5());
29914}
29915
29916inline std::string SHA_256(const std::string &s) {
29917 return message_digest(s, EVP_sha256());
29918}
29919
29920inline std::string SHA_512(const std::string &s) {
29921 return message_digest(s, EVP_sha512());
29922}
29923#endif
29924
29925#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
29926#ifdef _WIN32
29927// NOTE: This code came up with the following stackoverflow post:
29928// https://stackoverflow.com/questions/9507184/can-openssl-on-windows-use-the-system-certificate-store
29929inline bool load_system_certs_on_windows(X509_STORE *store) {
29930 auto hStore = CertOpenSystemStoreW((HCRYPTPROV_LEGACY)NULL, L"ROOT");
29931 if (!hStore) { return false; }
29932
29933 auto result = false;
29934 PCCERT_CONTEXT pContext = NULL;
29935 while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) !=
29936 nullptr) {
29937 auto encoded_cert =
29938 static_cast<const unsigned char *>(pContext->pbCertEncoded);
29939
29940 auto x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
29941 if (x509) {
29942 X509_STORE_add_cert(store, x509);
29943 X509_free(x509);
29944 result = true;
29945 }
29946 }
29947
29948 CertFreeCertificateContext(pContext);
29949 CertCloseStore(hStore, 0);
29950
29951 return result;
29952}
29953#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
29954#if TARGET_OS_OSX
29955template <typename T>
29956using CFObjectPtr =
29957 std::unique_ptr<typename std::remove_pointer<T>::type, void (*)(CFTypeRef)>;
29958
29959inline void cf_object_ptr_deleter(CFTypeRef obj) {
29960 if (obj) { CFRelease(obj); }
29961}
29962
29963inline bool retrieve_certs_from_keychain(CFObjectPtr<CFArrayRef> &certs) {
29964 CFStringRef keys[] = {kSecClass, kSecMatchLimit, kSecReturnRef};
29965 CFTypeRef values[] = {kSecClassCertificate, kSecMatchLimitAll,
29966 kCFBooleanTrue};
29967
29968 CFObjectPtr<CFDictionaryRef> query(
29969 CFDictionaryCreate(nullptr, reinterpret_cast<const void **>(keys), values,
29970 sizeof(keys) / sizeof(keys[0]),
29971 &kCFTypeDictionaryKeyCallBacks,
29972 &kCFTypeDictionaryValueCallBacks),
29973 cf_object_ptr_deleter);
29974
29975 if (!query) { return false; }
29976
29977 CFTypeRef security_items = nullptr;
29978 if (SecItemCopyMatching(query.get(), &security_items) != errSecSuccess ||
29979 CFArrayGetTypeID() != CFGetTypeID(security_items)) {
29980 return false;
29981 }
29982
29983 certs.reset(reinterpret_cast<CFArrayRef>(security_items));
29984 return true;
29985}
29986
29987inline bool retrieve_root_certs_from_keychain(CFObjectPtr<CFArrayRef> &certs) {
29988 CFArrayRef root_security_items = nullptr;
29989 if (SecTrustCopyAnchorCertificates(&root_security_items) != errSecSuccess) {
29990 return false;
29991 }
29992
29993 certs.reset(root_security_items);
29994 return true;
29995}
29996
29997inline bool add_certs_to_x509_store(CFArrayRef certs, X509_STORE *store) {
29998 auto result = false;
29999 for (auto i = 0; i < CFArrayGetCount(certs); ++i) {
30000 const auto cert = reinterpret_cast<const __SecCertificate *>(
30001 CFArrayGetValueAtIndex(certs, i));
30002
30003 if (SecCertificateGetTypeID() != CFGetTypeID(cert)) { continue; }
30004
30005 CFDataRef cert_data = nullptr;
30006 if (SecItemExport(cert, kSecFormatX509Cert, 0, nullptr, &cert_data) !=
30007 errSecSuccess) {
30008 continue;
30009 }
30010
30011 CFObjectPtr<CFDataRef> cert_data_ptr(cert_data, cf_object_ptr_deleter);
30012
30013 auto encoded_cert = static_cast<const unsigned char *>(
30014 CFDataGetBytePtr(cert_data_ptr.get()));
30015
30016 auto x509 =
30017 d2i_X509(NULL, &encoded_cert, CFDataGetLength(cert_data_ptr.get()));
30018
30019 if (x509) {
30020 X509_STORE_add_cert(store, x509);
30021 X509_free(x509);
30022 result = true;
30023 }
30024 }
30025
30026 return result;
30027}
30028
30029inline bool load_system_certs_on_macos(X509_STORE *store) {
30030 auto result = false;
30031 CFObjectPtr<CFArrayRef> certs(nullptr, cf_object_ptr_deleter);
30032 if (retrieve_certs_from_keychain(certs) && certs) {
30033 result = add_certs_to_x509_store(certs.get(), store);
30034 }
30035
30036 if (retrieve_root_certs_from_keychain(certs) && certs) {
30037 result = add_certs_to_x509_store(certs.get(), store) || result;
30038 }
30039
30040 return result;
30041}
30042#endif // TARGET_OS_OSX
30043#endif // _WIN32
30044#endif // CPPHTTPLIB_OPENSSL_SUPPORT
30045
30046#ifdef _WIN32
30047class WSInit {
30048public:
30049 WSInit() {
30050 WSADATA wsaData;
30051 if (WSAStartup(0x0002, &wsaData) == 0) is_valid_ = true;
30052 }
30053
30054 ~WSInit() {
30055 if (is_valid_) WSACleanup();
30056 }
30057
30058 bool is_valid_ = false;
30059};
30060
30061static WSInit wsinit_;
30062#endif
30063
30064#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
30065inline std::pair<std::string, std::string> make_digest_authentication_header(
30066 const Request &req, const std::map<std::string, std::string> &auth,
30067 size_t cnonce_count, const std::string &cnonce, const std::string &username,
30068 const std::string &password, bool is_proxy = false) {
30069 std::string nc;
30070 {
30071 std::stringstream ss;
30072 ss << std::setfill('0') << std::setw(8) << std::hex << cnonce_count;
30073 nc = ss.str();
30074 }
30075
30076 std::string qop;
30077 if (auth.find("qop") != auth.end()) {
30078 qop = auth.at("qop");
30079 if (qop.find("auth-int") != std::string::npos) {
30080 qop = "auth-int";
30081 } else if (qop.find("auth") != std::string::npos) {
30082 qop = "auth";
30083 } else {
30084 qop.clear();
30085 }
30086 }
30087
30088 std::string algo = "MD5";
30089 if (auth.find("algorithm") != auth.end()) { algo = auth.at("algorithm"); }
30090
30091 std::string response;
30092 {
30093 auto H = algo == "SHA-256" ? detail::SHA_256
30094 : algo == "SHA-512" ? detail::SHA_512
30095 : detail::MD5;
30096
30097 auto A1 = username + ":" + auth.at("realm") + ":" + password;
30098
30099 auto A2 = req.method + ":" + req.path;
30100 if (qop == "auth-int") { A2 += ":" + H(req.body); }
30101
30102 if (qop.empty()) {
30103 response = H(H(A1) + ":" + auth.at("nonce") + ":" + H(A2));
30104 } else {
30105 response = H(H(A1) + ":" + auth.at("nonce") + ":" + nc + ":" + cnonce +
30106 ":" + qop + ":" + H(A2));
30107 }
30108 }
30109
30110 auto opaque = (auth.find("opaque") != auth.end()) ? auth.at("opaque") : "";
30111
30112 auto field = "Digest username=\"" + username + "\", realm=\"" +
30113 auth.at("realm") + "\", nonce=\"" + auth.at("nonce") +
30114 "\", uri=\"" + req.path + "\", algorithm=" + algo +
30115 (qop.empty() ? ", response=\""
30116 : ", qop=" + qop + ", nc=" + nc + ", cnonce=\"" +
30117 cnonce + "\", response=\"") +
30118 response + "\"" +
30119 (opaque.empty() ? "" : ", opaque=\"" + opaque + "\"");
30120
30121 auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
30122 return std::make_pair(key, field);
30123}
30124#endif
30125
30126inline bool parse_www_authenticate(const Response &res,
30127 std::map<std::string, std::string> &auth,
30128 bool is_proxy) {
30129 auto auth_key = is_proxy ? "Proxy-Authenticate" : "WWW-Authenticate";
30130 if (res.has_header(auth_key)) {
30131 static auto re = std::regex(R"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~");
30132 auto s = res.get_header_value(auth_key);
30133 auto pos = s.find(' ');
30134 if (pos != std::string::npos) {
30135 auto type = s.substr(0, pos);
30136 if (type == "Basic") {
30137 return false;
30138 } else if (type == "Digest") {
30139 s = s.substr(pos + 1);
30140 auto beg = std::sregex_iterator(s.begin(), s.end(), re);
30141 for (auto i = beg; i != std::sregex_iterator(); ++i) {
30142 const auto &m = *i;
30143 auto key = s.substr(static_cast<size_t>(m.position(1)),
30144 static_cast<size_t>(m.length(1)));
30145 auto val = m.length(2) > 0
30146 ? s.substr(static_cast<size_t>(m.position(2)),
30147 static_cast<size_t>(m.length(2)))
30148 : s.substr(static_cast<size_t>(m.position(3)),
30149 static_cast<size_t>(m.length(3)));
30150 auth[key] = val;
30151 }
30152 return true;
30153 }
30154 }
30155 }
30156 return false;
30157}
30158
30160public:
30161 explicit ContentProviderAdapter(
30162 ContentProviderWithoutLength &&content_provider)
30163 : content_provider_(content_provider) {}
30164
30165 bool operator()(size_t offset, size_t, DataSink &sink) {
30166 return content_provider_(offset, sink);
30167 }
30168
30169private:
30170 ContentProviderWithoutLength content_provider_;
30171};
30172
30173} // namespace detail
30174
30175inline std::string hosted_at(const std::string &hostname) {
30176 std::vector<std::string> addrs;
30177 hosted_at(hostname, addrs);
30178 if (addrs.empty()) { return std::string(); }
30179 return addrs[0];
30180}
30181
30182inline void hosted_at(const std::string &hostname,
30183 std::vector<std::string> &addrs) {
30184 struct addrinfo hints;
30185 struct addrinfo *result;
30186
30187 memset(&hints, 0, sizeof(struct addrinfo));
30188 hints.ai_family = AF_UNSPEC;
30189 hints.ai_socktype = SOCK_STREAM;
30190 hints.ai_protocol = 0;
30191
30192 if (getaddrinfo(hostname.c_str(), nullptr, &hints, &result)) {
30193#if defined __linux__ && !defined __ANDROID__
30194 res_init();
30195#endif
30196 return;
30197 }
30198
30199 for (auto rp = result; rp; rp = rp->ai_next) {
30200 const auto &addr =
30201 *reinterpret_cast<struct sockaddr_storage *>(rp->ai_addr);
30202 std::string ip;
30203 auto dummy = -1;
30204 if (detail::get_ip_and_port(addr, sizeof(struct sockaddr_storage), ip,
30205 dummy)) {
30206 addrs.push_back(ip);
30207 }
30208 }
30209
30210 freeaddrinfo(result);
30211}
30212
30213inline std::string append_query_params(const std::string &path,
30214 const Params &params) {
30215 std::string path_with_query = path;
30216 const static std::regex re("[^?]+\\?.*");
30217 auto delm = std::regex_match(path, re) ? '&' : '?';
30218 path_with_query += delm + detail::params_to_query_str(params);
30219 return path_with_query;
30220}
30221
30222// Header utilities
30223inline std::pair<std::string, std::string>
30224make_range_header(const Ranges &ranges) {
30225 std::string field = "bytes=";
30226 auto i = 0;
30227 for (const auto &r : ranges) {
30228 if (i != 0) { field += ", "; }
30229 if (r.first != -1) { field += std::to_string(r.first); }
30230 field += '-';
30231 if (r.second != -1) { field += std::to_string(r.second); }
30232 i++;
30233 }
30234 return std::make_pair("Range", std::move(field));
30235}
30236
30237inline std::pair<std::string, std::string>
30238make_basic_authentication_header(const std::string &username,
30239 const std::string &password, bool is_proxy) {
30240 auto field = "Basic " + detail::base64_encode(username + ":" + password);
30241 auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
30242 return std::make_pair(key, std::move(field));
30243}
30244
30245inline std::pair<std::string, std::string>
30246make_bearer_token_authentication_header(const std::string &token,
30247 bool is_proxy = false) {
30248 auto field = "Bearer " + token;
30249 auto key = is_proxy ? "Proxy-Authorization" : "Authorization";
30250 return std::make_pair(key, std::move(field));
30251}
30252
30253// Request implementation
30254inline bool Request::has_header(const std::string &key) const {
30255 return detail::has_header(headers, key);
30256}
30257
30258inline std::string Request::get_header_value(const std::string &key,
30259 size_t id) const {
30260 return detail::get_header_value(headers, key, id, "");
30261}
30262
30263inline size_t Request::get_header_value_count(const std::string &key) const {
30264 auto r = headers.equal_range(key);
30265 return static_cast<size_t>(std::distance(r.first, r.second));
30266}
30267
30268inline void Request::set_header(const std::string &key,
30269 const std::string &val) {
30270 if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
30271 headers.emplace(key, val);
30272 }
30273}
30274
30275inline bool Request::has_param(const std::string &key) const {
30276 return params.find(key) != params.end();
30277}
30278
30279inline std::string Request::get_param_value(const std::string &key,
30280 size_t id) const {
30281 auto rng = params.equal_range(key);
30282 auto it = rng.first;
30283 std::advance(it, static_cast<ssize_t>(id));
30284 if (it != rng.second) { return it->second; }
30285 return std::string();
30286}
30287
30288inline size_t Request::get_param_value_count(const std::string &key) const {
30289 auto r = params.equal_range(key);
30290 return static_cast<size_t>(std::distance(r.first, r.second));
30291}
30292
30293inline bool Request::is_multipart_form_data() const {
30294 const auto &content_type = get_header_value("Content-Type");
30295 return !content_type.rfind("multipart/form-data", 0);
30296}
30297
30298inline bool Request::has_file(const std::string &key) const {
30299 return files.find(key) != files.end();
30300}
30301
30302inline MultipartFormData Request::get_file_value(const std::string &key) const {
30303 auto it = files.find(key);
30304 if (it != files.end()) { return it->second; }
30305 return MultipartFormData();
30306}
30307
30308inline std::vector<MultipartFormData>
30309Request::get_file_values(const std::string &key) const {
30310 std::vector<MultipartFormData> values;
30311 auto rng = files.equal_range(key);
30312 for (auto it = rng.first; it != rng.second; it++) {
30313 values.push_back(it->second);
30314 }
30315 return values;
30316}
30317
30318// Response implementation
30319inline bool Response::has_header(const std::string &key) const {
30320 return headers.find(key) != headers.end();
30321}
30322
30323inline std::string Response::get_header_value(const std::string &key,
30324 size_t id) const {
30325 return detail::get_header_value(headers, key, id, "");
30326}
30327
30328inline size_t Response::get_header_value_count(const std::string &key) const {
30329 auto r = headers.equal_range(key);
30330 return static_cast<size_t>(std::distance(r.first, r.second));
30331}
30332
30333inline void Response::set_header(const std::string &key,
30334 const std::string &val) {
30335 if (!detail::has_crlf(key) && !detail::has_crlf(val)) {
30336 headers.emplace(key, val);
30337 }
30338}
30339
30340inline void Response::set_redirect(const std::string &url, int stat) {
30341 if (!detail::has_crlf(url)) {
30342 set_header("Location", url);
30343 if (300 <= stat && stat < 400) {
30344 this->status = stat;
30345 } else {
30346 this->status = StatusCode::Found_302;
30347 }
30348 }
30349}
30350
30351inline void Response::set_content(const char *s, size_t n,
30352 const std::string &content_type) {
30353 body.assign(s, n);
30354
30355 auto rng = headers.equal_range("Content-Type");
30356 headers.erase(rng.first, rng.second);
30357 set_header("Content-Type", content_type);
30358}
30359
30360inline void Response::set_content(const std::string &s,
30361 const std::string &content_type) {
30362 set_content(s.data(), s.size(), content_type);
30363}
30364
30365inline void Response::set_content(std::string &&s,
30366 const std::string &content_type) {
30367 body = std::move(s);
30368
30369 auto rng = headers.equal_range("Content-Type");
30370 headers.erase(rng.first, rng.second);
30371 set_header("Content-Type", content_type);
30372}
30373
30374inline void Response::set_content_provider(
30375 size_t in_length, const std::string &content_type, ContentProvider provider,
30376 ContentProviderResourceReleaser resource_releaser) {
30377 set_header("Content-Type", content_type);
30378 content_length_ = in_length;
30379 if (in_length > 0) { content_provider_ = std::move(provider); }
30380 content_provider_resource_releaser_ = std::move(resource_releaser);
30381 is_chunked_content_provider_ = false;
30382}
30383
30384inline void Response::set_content_provider(
30385 const std::string &content_type, ContentProviderWithoutLength provider,
30386 ContentProviderResourceReleaser resource_releaser) {
30387 set_header("Content-Type", content_type);
30388 content_length_ = 0;
30389 content_provider_ = detail::ContentProviderAdapter(std::move(provider));
30390 content_provider_resource_releaser_ = std::move(resource_releaser);
30391 is_chunked_content_provider_ = false;
30392}
30393
30394inline void Response::set_chunked_content_provider(
30395 const std::string &content_type, ContentProviderWithoutLength provider,
30396 ContentProviderResourceReleaser resource_releaser) {
30397 set_header("Content-Type", content_type);
30398 content_length_ = 0;
30399 content_provider_ = detail::ContentProviderAdapter(std::move(provider));
30400 content_provider_resource_releaser_ = std::move(resource_releaser);
30401 is_chunked_content_provider_ = true;
30402}
30403
30404// Result implementation
30405inline bool Result::has_request_header(const std::string &key) const {
30406 return request_headers_.find(key) != request_headers_.end();
30407}
30408
30409inline std::string Result::get_request_header_value(const std::string &key,
30410 size_t id) const {
30411 return detail::get_header_value(request_headers_, key, id, "");
30412}
30413
30414inline size_t
30415Result::get_request_header_value_count(const std::string &key) const {
30416 auto r = request_headers_.equal_range(key);
30417 return static_cast<size_t>(std::distance(r.first, r.second));
30418}
30419
30420// Stream implementation
30421inline ssize_t Stream::write(const char *ptr) {
30422 return write(ptr, strlen(ptr));
30423}
30424
30425inline ssize_t Stream::write(const std::string &s) {
30426 return write(s.data(), s.size());
30427}
30428
30429namespace detail {
30430
30431// Socket stream implementation
30432inline SocketStream::SocketStream(socket_t sock, time_t read_timeout_sec,
30433 time_t read_timeout_usec,
30434 time_t write_timeout_sec,
30435 time_t write_timeout_usec)
30436 : sock_(sock), read_timeout_sec_(read_timeout_sec),
30437 read_timeout_usec_(read_timeout_usec),
30438 write_timeout_sec_(write_timeout_sec),
30439 write_timeout_usec_(write_timeout_usec), read_buff_(read_buff_size_, 0) {}
30440
30441inline SocketStream::~SocketStream() = default;
30442
30443inline bool SocketStream::is_readable() const {
30444 return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
30445}
30446
30447inline bool SocketStream::is_writable() const {
30448 return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 &&
30449 is_socket_alive(sock_);
30450}
30451
30452inline ssize_t SocketStream::read(char *ptr, size_t size) {
30453#ifdef _WIN32
30454 size =
30455 (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
30456#else
30457 size = (std::min)(size,
30458 static_cast<size_t>((std::numeric_limits<ssize_t>::max)()));
30459#endif
30460
30461 if (read_buff_off_ < read_buff_content_size_) {
30462 auto remaining_size = read_buff_content_size_ - read_buff_off_;
30463 if (size <= remaining_size) {
30464 memcpy(ptr, read_buff_.data() + read_buff_off_, size);
30465 read_buff_off_ += size;
30466 return static_cast<ssize_t>(size);
30467 } else {
30468 memcpy(ptr, read_buff_.data() + read_buff_off_, remaining_size);
30469 read_buff_off_ += remaining_size;
30470 return static_cast<ssize_t>(remaining_size);
30471 }
30472 }
30473
30474 if (!is_readable()) { return -1; }
30475
30476 read_buff_off_ = 0;
30477 read_buff_content_size_ = 0;
30478
30479 if (size < read_buff_size_) {
30480 auto n = read_socket(sock_, read_buff_.data(), read_buff_size_,
30481 CPPHTTPLIB_RECV_FLAGS);
30482 if (n <= 0) {
30483 return n;
30484 } else if (n <= static_cast<ssize_t>(size)) {
30485 memcpy(ptr, read_buff_.data(), static_cast<size_t>(n));
30486 return n;
30487 } else {
30488 memcpy(ptr, read_buff_.data(), size);
30489 read_buff_off_ = size;
30490 read_buff_content_size_ = static_cast<size_t>(n);
30491 return static_cast<ssize_t>(size);
30492 }
30493 } else {
30494 return read_socket(sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS);
30495 }
30496}
30497
30498inline ssize_t SocketStream::write(const char *ptr, size_t size) {
30499 if (!is_writable()) { return -1; }
30500
30501#if defined(_WIN32) && !defined(_WIN64)
30502 size =
30503 (std::min)(size, static_cast<size_t>((std::numeric_limits<int>::max)()));
30504#endif
30505
30506 return send_socket(sock_, ptr, size, CPPHTTPLIB_SEND_FLAGS);
30507}
30508
30509inline void SocketStream::get_remote_ip_and_port(std::string &ip,
30510 int &port) const {
30511 return detail::get_remote_ip_and_port(sock_, ip, port);
30512}
30513
30514inline void SocketStream::get_local_ip_and_port(std::string &ip,
30515 int &port) const {
30516 return detail::get_local_ip_and_port(sock_, ip, port);
30517}
30518
30519inline socket_t SocketStream::socket() const { return sock_; }
30520
30521// Buffer stream implementation
30522inline bool BufferStream::is_readable() const { return true; }
30523
30524inline bool BufferStream::is_writable() const { return true; }
30525
30526inline ssize_t BufferStream::read(char *ptr, size_t size) {
30527#if defined(_MSC_VER) && _MSC_VER < 1910
30528 auto len_read = buffer._Copy_s(ptr, size, size, position);
30529#else
30530 auto len_read = buffer.copy(ptr, size, position);
30531#endif
30532 position += static_cast<size_t>(len_read);
30533 return static_cast<ssize_t>(len_read);
30534}
30535
30536inline ssize_t BufferStream::write(const char *ptr, size_t size) {
30537 buffer.append(ptr, size);
30538 return static_cast<ssize_t>(size);
30539}
30540
30541inline void BufferStream::get_remote_ip_and_port(std::string & /*ip*/,
30542 int & /*port*/) const {}
30543
30544inline void BufferStream::get_local_ip_and_port(std::string & /*ip*/,
30545 int & /*port*/) const {}
30546
30547inline socket_t BufferStream::socket() const { return 0; }
30548
30549inline const std::string &BufferStream::get_buffer() const { return buffer; }
30550
30551inline PathParamsMatcher::PathParamsMatcher(const std::string &pattern) {
30552 // One past the last ending position of a path param substring
30553 std::size_t last_param_end = 0;
30554
30555#ifndef CPPHTTPLIB_NO_EXCEPTIONS
30556 // Needed to ensure that parameter names are unique during matcher
30557 // construction
30558 // If exceptions are disabled, only last duplicate path
30559 // parameter will be set
30560 std::unordered_set<std::string> param_name_set;
30561#endif
30562
30563 while (true) {
30564 const auto marker_pos = pattern.find(marker, last_param_end);
30565 if (marker_pos == std::string::npos) { break; }
30566
30567 static_fragments_.push_back(
30568 pattern.substr(last_param_end, marker_pos - last_param_end));
30569
30570 const auto param_name_start = marker_pos + 1;
30571
30572 auto sep_pos = pattern.find(separator, param_name_start);
30573 if (sep_pos == std::string::npos) { sep_pos = pattern.length(); }
30574
30575 auto param_name =
30576 pattern.substr(param_name_start, sep_pos - param_name_start);
30577
30578#ifndef CPPHTTPLIB_NO_EXCEPTIONS
30579 if (param_name_set.find(param_name) != param_name_set.cend()) {
30580 std::string msg = "Encountered path parameter '" + param_name +
30581 "' multiple times in route pattern '" + pattern + "'.";
30582 throw std::invalid_argument(msg);
30583 }
30584#endif
30585
30586 param_names_.push_back(std::move(param_name));
30587
30588 last_param_end = sep_pos + 1;
30589 }
30590
30591 if (last_param_end < pattern.length()) {
30592 static_fragments_.push_back(pattern.substr(last_param_end));
30593 }
30594}
30595
30596inline bool PathParamsMatcher::match(Request &request) const {
30597 request.matches = std::smatch();
30598 request.path_params.clear();
30599 request.path_params.reserve(param_names_.size());
30600
30601 // One past the position at which the path matched the pattern last time
30602 std::size_t starting_pos = 0;
30603 for (size_t i = 0; i < static_fragments_.size(); ++i) {
30604 const auto &fragment = static_fragments_[i];
30605
30606 if (starting_pos + fragment.length() > request.path.length()) {
30607 return false;
30608 }
30609
30610 // Avoid unnecessary allocation by using strncmp instead of substr +
30611 // comparison
30612 if (std::strncmp(request.path.c_str() + starting_pos, fragment.c_str(),
30613 fragment.length()) != 0) {
30614 return false;
30615 }
30616
30617 starting_pos += fragment.length();
30618
30619 // Should only happen when we have a static fragment after a param
30620 // Example: '/users/:id/subscriptions'
30621 // The 'subscriptions' fragment here does not have a corresponding param
30622 if (i >= param_names_.size()) { continue; }
30623
30624 auto sep_pos = request.path.find(separator, starting_pos);
30625 if (sep_pos == std::string::npos) { sep_pos = request.path.length(); }
30626
30627 const auto &param_name = param_names_[i];
30628
30629 request.path_params.emplace(
30630 param_name, request.path.substr(starting_pos, sep_pos - starting_pos));
30631
30632 // Mark everythin up to '/' as matched
30633 starting_pos = sep_pos + 1;
30634 }
30635 // Returns false if the path is longer than the pattern
30636 return starting_pos >= request.path.length();
30637}
30638
30639inline bool RegexMatcher::match(Request &request) const {
30640 request.path_params.clear();
30641 return std::regex_match(request.path, request.matches, regex_);
30642}
30643
30644} // namespace detail
30645
30646// HTTP server implementation
30647inline Server::Server()
30648 : new_task_queue(
30649 [] { return new ThreadPool(CPPHTTPLIB_THREAD_POOL_COUNT); }) {
30650#ifndef _WIN32
30651 signal(SIGPIPE, SIG_IGN);
30652#endif
30653}
30654
30655inline Server::~Server() = default;
30656
30657inline std::unique_ptr<detail::MatcherBase>
30658Server::make_matcher(const std::string &pattern) {
30659 if (pattern.find("/:") != std::string::npos) {
30660 return detail::make_unique<detail::PathParamsMatcher>(pattern);
30661 } else {
30662 return detail::make_unique<detail::RegexMatcher>(pattern);
30663 }
30664}
30665
30666inline Server &Server::Get(const std::string &pattern, Handler handler) {
30667 get_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
30668 return *this;
30669}
30670
30671inline Server &Server::Post(const std::string &pattern, Handler handler) {
30672 post_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
30673 return *this;
30674}
30675
30676inline Server &Server::Post(const std::string &pattern,
30677 HandlerWithContentReader handler) {
30678 post_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
30679 std::move(handler));
30680 return *this;
30681}
30682
30683inline Server &Server::Put(const std::string &pattern, Handler handler) {
30684 put_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
30685 return *this;
30686}
30687
30688inline Server &Server::Put(const std::string &pattern,
30689 HandlerWithContentReader handler) {
30690 put_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
30691 std::move(handler));
30692 return *this;
30693}
30694
30695inline Server &Server::Patch(const std::string &pattern, Handler handler) {
30696 patch_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
30697 return *this;
30698}
30699
30700inline Server &Server::Patch(const std::string &pattern,
30701 HandlerWithContentReader handler) {
30702 patch_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
30703 std::move(handler));
30704 return *this;
30705}
30706
30707inline Server &Server::Delete(const std::string &pattern, Handler handler) {
30708 delete_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
30709 return *this;
30710}
30711
30712inline Server &Server::Delete(const std::string &pattern,
30713 HandlerWithContentReader handler) {
30714 delete_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
30715 std::move(handler));
30716 return *this;
30717}
30718
30719inline Server &Server::Options(const std::string &pattern, Handler handler) {
30720 options_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
30721 return *this;
30722}
30723
30724inline bool Server::set_base_dir(const std::string &dir,
30725 const std::string &mount_point) {
30726 return set_mount_point(mount_point, dir);
30727}
30728
30729inline bool Server::set_mount_point(const std::string &mount_point,
30730 const std::string &dir, Headers headers) {
30731 if (detail::is_dir(dir)) {
30732 std::string mnt = !mount_point.empty() ? mount_point : "/";
30733 if (!mnt.empty() && mnt[0] == '/') {
30734 base_dirs_.push_back({mnt, dir, std::move(headers)});
30735 return true;
30736 }
30737 }
30738 return false;
30739}
30740
30741inline bool Server::remove_mount_point(const std::string &mount_point) {
30742 for (auto it = base_dirs_.begin(); it != base_dirs_.end(); ++it) {
30743 if (it->mount_point == mount_point) {
30744 base_dirs_.erase(it);
30745 return true;
30746 }
30747 }
30748 return false;
30749}
30750
30751inline Server &
30752Server::set_file_extension_and_mimetype_mapping(const std::string &ext,
30753 const std::string &mime) {
30754 file_extension_and_mimetype_map_[ext] = mime;
30755 return *this;
30756}
30757
30758inline Server &Server::set_default_file_mimetype(const std::string &mime) {
30759 default_file_mimetype_ = mime;
30760 return *this;
30761}
30762
30763inline Server &Server::set_file_request_handler(Handler handler) {
30764 file_request_handler_ = std::move(handler);
30765 return *this;
30766}
30767
30768inline Server &Server::set_error_handler_core(HandlerWithResponse handler,
30769 std::true_type) {
30770 error_handler_ = std::move(handler);
30771 return *this;
30772}
30773
30774inline Server &Server::set_error_handler_core(Handler handler,
30775 std::false_type) {
30776 error_handler_ = [handler](const Request &req, Response &res) {
30777 handler(req, res);
30778 return HandlerResponse::Handled;
30779 };
30780 return *this;
30781}
30782
30783inline Server &Server::set_exception_handler(ExceptionHandler handler) {
30784 exception_handler_ = std::move(handler);
30785 return *this;
30786}
30787
30788inline Server &Server::set_pre_routing_handler(HandlerWithResponse handler) {
30789 pre_routing_handler_ = std::move(handler);
30790 return *this;
30791}
30792
30793inline Server &Server::set_post_routing_handler(Handler handler) {
30794 post_routing_handler_ = std::move(handler);
30795 return *this;
30796}
30797
30798inline Server &Server::set_logger(Logger logger) {
30799 logger_ = std::move(logger);
30800 return *this;
30801}
30802
30803inline Server &
30804Server::set_expect_100_continue_handler(Expect100ContinueHandler handler) {
30805 expect_100_continue_handler_ = std::move(handler);
30806 return *this;
30807}
30808
30809inline Server &Server::set_address_family(int family) {
30810 address_family_ = family;
30811 return *this;
30812}
30813
30814inline Server &Server::set_tcp_nodelay(bool on) {
30815 tcp_nodelay_ = on;
30816 return *this;
30817}
30818
30819inline Server &Server::set_socket_options(SocketOptions socket_options) {
30820 socket_options_ = std::move(socket_options);
30821 return *this;
30822}
30823
30824inline Server &Server::set_default_headers(Headers headers) {
30825 default_headers_ = std::move(headers);
30826 return *this;
30827}
30828
30829inline Server &Server::set_header_writer(
30830 std::function<ssize_t(Stream &, Headers &)> const &writer) {
30831 header_writer_ = writer;
30832 return *this;
30833}
30834
30835inline Server &Server::set_keep_alive_max_count(size_t count) {
30836 keep_alive_max_count_ = count;
30837 return *this;
30838}
30839
30840inline Server &Server::set_keep_alive_timeout(time_t sec) {
30841 keep_alive_timeout_sec_ = sec;
30842 return *this;
30843}
30844
30845inline Server &Server::set_read_timeout(time_t sec, time_t usec) {
30846 read_timeout_sec_ = sec;
30847 read_timeout_usec_ = usec;
30848 return *this;
30849}
30850
30851inline Server &Server::set_write_timeout(time_t sec, time_t usec) {
30852 write_timeout_sec_ = sec;
30853 write_timeout_usec_ = usec;
30854 return *this;
30855}
30856
30857inline Server &Server::set_idle_interval(time_t sec, time_t usec) {
30858 idle_interval_sec_ = sec;
30859 idle_interval_usec_ = usec;
30860 return *this;
30861}
30862
30863inline Server &Server::set_payload_max_length(size_t length) {
30864 payload_max_length_ = length;
30865 return *this;
30866}
30867
30868inline bool Server::bind_to_port(const std::string &host, int port,
30869 int socket_flags) {
30870 return bind_internal(host, port, socket_flags) >= 0;
30871}
30872inline int Server::bind_to_any_port(const std::string &host, int socket_flags) {
30873 return bind_internal(host, 0, socket_flags);
30874}
30875
30876inline bool Server::listen_after_bind() {
30877 auto se = detail::scope_exit([&]() { done_ = true; });
30878 return listen_internal();
30879}
30880
30881inline bool Server::listen(const std::string &host, int port,
30882 int socket_flags) {
30883 auto se = detail::scope_exit([&]() { done_ = true; });
30884 return bind_to_port(host, port, socket_flags) && listen_internal();
30885}
30886
30887inline bool Server::is_running() const { return is_running_; }
30888
30889inline void Server::wait_until_ready() const {
30890 while (!is_running() && !done_) {
30891 std::this_thread::sleep_for(std::chrono::milliseconds{1});
30892 }
30893}
30894
30895inline void Server::stop() {
30896 if (is_running_) {
30897 assert(svr_sock_ != INVALID_SOCKET);
30898 std::atomic<socket_t> sock(svr_sock_.exchange(INVALID_SOCKET));
30899 detail::shutdown_socket(sock);
30900 detail::close_socket(sock);
30901 }
30902}
30903
30904inline bool Server::parse_request_line(const char *s, Request &req) const {
30905 auto len = strlen(s);
30906 if (len < 2 || s[len - 2] != '\r' || s[len - 1] != '\n') { return false; }
30907 len -= 2;
30908
30909 {
30910 size_t count = 0;
30911
30912 detail::split(s, s + len, ' ', [&](const char *b, const char *e) {
30913 switch (count) {
30914 case 0: req.method = std::string(b, e); break;
30915 case 1: req.target = std::string(b, e); break;
30916 case 2: req.version = std::string(b, e); break;
30917 default: break;
30918 }
30919 count++;
30920 });
30921
30922 if (count != 3) { return false; }
30923 }
30924
30925 static const std::set<std::string> methods{
30926 "GET", "HEAD", "POST", "PUT", "DELETE",
30927 "CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"};
30928
30929 if (methods.find(req.method) == methods.end()) { return false; }
30930
30931 if (req.version != "HTTP/1.1" && req.version != "HTTP/1.0") { return false; }
30932
30933 {
30934 // Skip URL fragment
30935 for (size_t i = 0; i < req.target.size(); i++) {
30936 if (req.target[i] == '#') {
30937 req.target.erase(i);
30938 break;
30939 }
30940 }
30941
30942 detail::divide(req.target, '?',
30943 [&](const char *lhs_data, std::size_t lhs_size,
30944 const char *rhs_data, std::size_t rhs_size) {
30945 req.path = detail::decode_url(
30946 std::string(lhs_data, lhs_size), false);
30947 detail::parse_query_text(rhs_data, rhs_size, req.params);
30948 });
30949 }
30950
30951 return true;
30952}
30953
30954inline bool Server::write_response(Stream &strm, bool close_connection,
30955 Request &req, Response &res) {
30956 // NOTE: `req.ranges` should be empty, otherwise it will be applied
30957 // incorrectly to the error content.
30958 req.ranges.clear();
30959 return write_response_core(strm, close_connection, req, res, false);
30960}
30961
30962inline bool Server::write_response_with_content(Stream &strm,
30963 bool close_connection,
30964 const Request &req,
30965 Response &res) {
30966 return write_response_core(strm, close_connection, req, res, true);
30967}
30968
30969inline bool Server::write_response_core(Stream &strm, bool close_connection,
30970 const Request &req, Response &res,
30971 bool need_apply_ranges) {
30972 assert(res.status != -1);
30973
30974 if (400 <= res.status && error_handler_ &&
30975 error_handler_(req, res) == HandlerResponse::Handled) {
30976 need_apply_ranges = true;
30977 }
30978
30979 std::string content_type;
30980 std::string boundary;
30981 if (need_apply_ranges) { apply_ranges(req, res, content_type, boundary); }
30982
30983 // Prepare additional headers
30984 if (close_connection || req.get_header_value("Connection") == "close") {
30985 res.set_header("Connection", "close");
30986 } else {
30987 std::stringstream ss;
30988 ss << "timeout=" << keep_alive_timeout_sec_
30989 << ", max=" << keep_alive_max_count_;
30990 res.set_header("Keep-Alive", ss.str());
30991 }
30992
30993 if (!res.has_header("Content-Type") &&
30994 (!res.body.empty() || res.content_length_ > 0 || res.content_provider_)) {
30995 res.set_header("Content-Type", "text/plain");
30996 }
30997
30998 if (!res.has_header("Content-Length") && res.body.empty() &&
30999 !res.content_length_ && !res.content_provider_) {
31000 res.set_header("Content-Length", "0");
31001 }
31002
31003 if (!res.has_header("Accept-Ranges") && req.method == "HEAD") {
31004 res.set_header("Accept-Ranges", "bytes");
31005 }
31006
31007 if (post_routing_handler_) { post_routing_handler_(req, res); }
31008
31009 // Response line and headers
31010 {
31011 detail::BufferStream bstrm;
31012
31013 if (!bstrm.write_format("HTTP/1.1 %d %s\r\n", res.status,
31014 status_message(res.status))) {
31015 return false;
31016 }
31017
31018 if (!header_writer_(bstrm, res.headers)) { return false; }
31019
31020 // Flush buffer
31021 auto &data = bstrm.get_buffer();
31022 detail::write_data(strm, data.data(), data.size());
31023 }
31024
31025 // Body
31026 auto ret = true;
31027 if (req.method != "HEAD") {
31028 if (!res.body.empty()) {
31029 if (!detail::write_data(strm, res.body.data(), res.body.size())) {
31030 ret = false;
31031 }
31032 } else if (res.content_provider_) {
31033 if (write_content_with_provider(strm, req, res, boundary, content_type)) {
31034 res.content_provider_success_ = true;
31035 } else {
31036 ret = false;
31037 }
31038 }
31039 }
31040
31041 // Log
31042 if (logger_) { logger_(req, res); }
31043
31044 return ret;
31045}
31046
31047inline bool
31048Server::write_content_with_provider(Stream &strm, const Request &req,
31049 Response &res, const std::string &boundary,
31050 const std::string &content_type) {
31051 auto is_shutting_down = [this]() {
31052 return this->svr_sock_ == INVALID_SOCKET;
31053 };
31054
31055 if (res.content_length_ > 0) {
31056 if (req.ranges.empty()) {
31057 return detail::write_content(strm, res.content_provider_, 0,
31058 res.content_length_, is_shutting_down);
31059 } else if (req.ranges.size() == 1) {
31060 auto offset_and_length = detail::get_range_offset_and_length(
31061 req.ranges[0], res.content_length_);
31062
31063 return detail::write_content(strm, res.content_provider_,
31064 offset_and_length.first,
31065 offset_and_length.second, is_shutting_down);
31066 } else {
31067 return detail::write_multipart_ranges_data(
31068 strm, req, res, boundary, content_type, res.content_length_,
31069 is_shutting_down);
31070 }
31071 } else {
31072 if (res.is_chunked_content_provider_) {
31073 auto type = detail::encoding_type(req, res);
31074
31075 std::unique_ptr<detail::compressor> compressor;
31076 if (type == detail::EncodingType::Gzip) {
31077#ifdef CPPHTTPLIB_ZLIB_SUPPORT
31078 compressor = detail::make_unique<detail::gzip_compressor>();
31079#endif
31080 } else if (type == detail::EncodingType::Brotli) {
31081#ifdef CPPHTTPLIB_BROTLI_SUPPORT
31082 compressor = detail::make_unique<detail::brotli_compressor>();
31083#endif
31084 } else {
31085 compressor = detail::make_unique<detail::nocompressor>();
31086 }
31087 assert(compressor != nullptr);
31088
31089 return detail::write_content_chunked(strm, res.content_provider_,
31090 is_shutting_down, *compressor);
31091 } else {
31092 return detail::write_content_without_length(strm, res.content_provider_,
31093 is_shutting_down);
31094 }
31095 }
31096}
31097
31098inline bool Server::read_content(Stream &strm, Request &req, Response &res) {
31099 MultipartFormDataMap::iterator cur;
31100 auto file_count = 0;
31101 if (read_content_core(
31102 strm, req, res,
31103 // Regular
31104 [&](const char *buf, size_t n) {
31105 if (req.body.size() + n > req.body.max_size()) { return false; }
31106 req.body.append(buf, n);
31107 return true;
31108 },
31109 // Multipart
31110 [&](const MultipartFormData &file) {
31111 if (file_count++ == CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT) {
31112 return false;
31113 }
31114 cur = req.files.emplace(file.name, file);
31115 return true;
31116 },
31117 [&](const char *buf, size_t n) {
31118 auto &content = cur->second.content;
31119 if (content.size() + n > content.max_size()) { return false; }
31120 content.append(buf, n);
31121 return true;
31122 })) {
31123 const auto &content_type = req.get_header_value("Content-Type");
31124 if (!content_type.find("application/x-www-form-urlencoded")) {
31125 if (req.body.size() > CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH) {
31126 res.status = StatusCode::PayloadTooLarge_413; // NOTE: should be 414?
31127 return false;
31128 }
31129 detail::parse_query_text(req.body, req.params);
31130 }
31131 return true;
31132 }
31133 return false;
31134}
31135
31136inline bool Server::read_content_with_content_receiver(
31137 Stream &strm, Request &req, Response &res, ContentReceiver receiver,
31138 MultipartContentHeader multipart_header,
31139 ContentReceiver multipart_receiver) {
31140 return read_content_core(strm, req, res, std::move(receiver),
31141 std::move(multipart_header),
31142 std::move(multipart_receiver));
31143}
31144
31145inline bool
31146Server::read_content_core(Stream &strm, Request &req, Response &res,
31147 ContentReceiver receiver,
31148 MultipartContentHeader multipart_header,
31149 ContentReceiver multipart_receiver) const {
31150 detail::MultipartFormDataParser multipart_form_data_parser;
31151 ContentReceiverWithProgress out;
31152
31153 if (req.is_multipart_form_data()) {
31154 const auto &content_type = req.get_header_value("Content-Type");
31155 std::string boundary;
31156 if (!detail::parse_multipart_boundary(content_type, boundary)) {
31157 res.status = StatusCode::BadRequest_400;
31158 return false;
31159 }
31160
31161 multipart_form_data_parser.set_boundary(std::move(boundary));
31162 out = [&](const char *buf, size_t n, uint64_t /*off*/, uint64_t /*len*/) {
31163 /* For debug
31164 size_t pos = 0;
31165 while (pos < n) {
31166 auto read_size = (std::min)<size_t>(1, n - pos);
31167 auto ret = multipart_form_data_parser.parse(
31168 buf + pos, read_size, multipart_receiver, multipart_header);
31169 if (!ret) { return false; }
31170 pos += read_size;
31171 }
31172 return true;
31173 */
31174 return multipart_form_data_parser.parse(buf, n, multipart_receiver,
31175 multipart_header);
31176 };
31177 } else {
31178 out = [receiver](const char *buf, size_t n, uint64_t /*off*/,
31179 uint64_t /*len*/) { return receiver(buf, n); };
31180 }
31181
31182 if (req.method == "DELETE" && !req.has_header("Content-Length")) {
31183 return true;
31184 }
31185
31186 if (!detail::read_content(strm, req, payload_max_length_, res.status, nullptr,
31187 out, true)) {
31188 return false;
31189 }
31190
31191 if (req.is_multipart_form_data()) {
31192 if (!multipart_form_data_parser.is_valid()) {
31193 res.status = StatusCode::BadRequest_400;
31194 return false;
31195 }
31196 }
31197
31198 return true;
31199}
31200
31201inline bool Server::handle_file_request(const Request &req, Response &res,
31202 bool head) {
31203 for (const auto &entry : base_dirs_) {
31204 // Prefix match
31205 if (!req.path.compare(0, entry.mount_point.size(), entry.mount_point)) {
31206 std::string sub_path = "/" + req.path.substr(entry.mount_point.size());
31207 if (detail::is_valid_path(sub_path)) {
31208 auto path = entry.base_dir + sub_path;
31209 if (path.back() == '/') { path += "index.html"; }
31210
31211 if (detail::is_file(path)) {
31212 for (const auto &kv : entry.headers) {
31213 res.set_header(kv.first, kv.second);
31214 }
31215
31216 auto mm = std::make_shared<detail::mmap>(path.c_str());
31217 if (!mm->is_open()) { return false; }
31218
31219 res.set_content_provider(
31220 mm->size(),
31221 detail::find_content_type(path, file_extension_and_mimetype_map_,
31222 default_file_mimetype_),
31223 [mm](size_t offset, size_t length, DataSink &sink) -> bool {
31224 sink.write(mm->data() + offset, length);
31225 return true;
31226 });
31227
31228 if (!head && file_request_handler_) {
31229 file_request_handler_(req, res);
31230 }
31231
31232 return true;
31233 }
31234 }
31235 }
31236 }
31237 return false;
31238}
31239
31240inline socket_t
31241Server::create_server_socket(const std::string &host, int port,
31242 int socket_flags,
31243 SocketOptions socket_options) const {
31244 return detail::create_socket(
31245 host, std::string(), port, address_family_, socket_flags, tcp_nodelay_,
31246 std::move(socket_options),
31247 [](socket_t sock, struct addrinfo &ai) -> bool {
31248 if (::bind(sock, ai.ai_addr, static_cast<socklen_t>(ai.ai_addrlen))) {
31249 return false;
31250 }
31251 if (::listen(sock, CPPHTTPLIB_LISTEN_BACKLOG)) { return false; }
31252 return true;
31253 });
31254}
31255
31256inline int Server::bind_internal(const std::string &host, int port,
31257 int socket_flags) {
31258 if (!is_valid()) { return -1; }
31259
31260 svr_sock_ = create_server_socket(host, port, socket_flags, socket_options_);
31261 if (svr_sock_ == INVALID_SOCKET) { return -1; }
31262
31263 if (port == 0) {
31264 struct sockaddr_storage addr;
31265 socklen_t addr_len = sizeof(addr);
31266 if (getsockname(svr_sock_, reinterpret_cast<struct sockaddr *>(&addr),
31267 &addr_len) == -1) {
31268 return -1;
31269 }
31270 if (addr.ss_family == AF_INET) {
31271 return ntohs(reinterpret_cast<struct sockaddr_in *>(&addr)->sin_port);
31272 } else if (addr.ss_family == AF_INET6) {
31273 return ntohs(reinterpret_cast<struct sockaddr_in6 *>(&addr)->sin6_port);
31274 } else {
31275 return -1;
31276 }
31277 } else {
31278 return port;
31279 }
31280}
31281
31282inline bool Server::listen_internal() {
31283 auto ret = true;
31284 is_running_ = true;
31285 auto se = detail::scope_exit([&]() { is_running_ = false; });
31286
31287 {
31288 std::unique_ptr<TaskQueue> task_queue(new_task_queue());
31289
31290 while (svr_sock_ != INVALID_SOCKET) {
31291#ifndef _WIN32
31292 if (idle_interval_sec_ > 0 || idle_interval_usec_ > 0) {
31293#endif
31294 auto val = detail::select_read(svr_sock_, idle_interval_sec_,
31295 idle_interval_usec_);
31296 if (val == 0) { // Timeout
31297 task_queue->on_idle();
31298 continue;
31299 }
31300#ifndef _WIN32
31301 }
31302#endif
31303 socket_t sock = accept(svr_sock_, nullptr, nullptr);
31304
31305 if (sock == INVALID_SOCKET) {
31306 if (errno == EMFILE) {
31307 // The per-process limit of open file descriptors has been reached.
31308 // Try to accept new connections after a short sleep.
31309 std::this_thread::sleep_for(std::chrono::milliseconds(1));
31310 continue;
31311 } else if (errno == EINTR || errno == EAGAIN) {
31312 continue;
31313 }
31314 if (svr_sock_ != INVALID_SOCKET) {
31315 detail::close_socket(svr_sock_);
31316 ret = false;
31317 } else {
31318 ; // The server socket was closed by user.
31319 }
31320 break;
31321 }
31322
31323 {
31324#ifdef _WIN32
31325 auto timeout = static_cast<uint32_t>(read_timeout_sec_ * 1000 +
31326 read_timeout_usec_ / 1000);
31327 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
31328 reinterpret_cast<const char *>(&timeout), sizeof(timeout));
31329#else
31330 timeval tv;
31331 tv.tv_sec = static_cast<long>(read_timeout_sec_);
31332 tv.tv_usec = static_cast<decltype(tv.tv_usec)>(read_timeout_usec_);
31333 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
31334 reinterpret_cast<const void *>(&tv), sizeof(tv));
31335#endif
31336 }
31337 {
31338
31339#ifdef _WIN32
31340 auto timeout = static_cast<uint32_t>(write_timeout_sec_ * 1000 +
31341 write_timeout_usec_ / 1000);
31342 setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
31343 reinterpret_cast<const char *>(&timeout), sizeof(timeout));
31344#else
31345 timeval tv;
31346 tv.tv_sec = static_cast<long>(write_timeout_sec_);
31347 tv.tv_usec = static_cast<decltype(tv.tv_usec)>(write_timeout_usec_);
31348 setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
31349 reinterpret_cast<const void *>(&tv), sizeof(tv));
31350#endif
31351 }
31352
31353 if (!task_queue->enqueue(
31354 [this, sock]() { process_and_close_socket(sock); })) {
31355 detail::shutdown_socket(sock);
31356 detail::close_socket(sock);
31357 }
31358 }
31359
31360 task_queue->shutdown();
31361 }
31362
31363 return ret;
31364}
31365
31366inline bool Server::routing(Request &req, Response &res, Stream &strm) {
31367 if (pre_routing_handler_ &&
31368 pre_routing_handler_(req, res) == HandlerResponse::Handled) {
31369 return true;
31370 }
31371
31372 // File handler
31373 auto is_head_request = req.method == "HEAD";
31374 if ((req.method == "GET" || is_head_request) &&
31375 handle_file_request(req, res, is_head_request)) {
31376 return true;
31377 }
31378
31379 if (detail::expect_content(req)) {
31380 // Content reader handler
31381 {
31382 ContentReader reader(
31383 [&](ContentReceiver receiver) {
31384 return read_content_with_content_receiver(
31385 strm, req, res, std::move(receiver), nullptr, nullptr);
31386 },
31387 [&](MultipartContentHeader header, ContentReceiver receiver) {
31388 return read_content_with_content_receiver(strm, req, res, nullptr,
31389 std::move(header),
31390 std::move(receiver));
31391 });
31392
31393 if (req.method == "POST") {
31394 if (dispatch_request_for_content_reader(
31395 req, res, std::move(reader),
31396 post_handlers_for_content_reader_)) {
31397 return true;
31398 }
31399 } else if (req.method == "PUT") {
31400 if (dispatch_request_for_content_reader(
31401 req, res, std::move(reader),
31402 put_handlers_for_content_reader_)) {
31403 return true;
31404 }
31405 } else if (req.method == "PATCH") {
31406 if (dispatch_request_for_content_reader(
31407 req, res, std::move(reader),
31408 patch_handlers_for_content_reader_)) {
31409 return true;
31410 }
31411 } else if (req.method == "DELETE") {
31412 if (dispatch_request_for_content_reader(
31413 req, res, std::move(reader),
31414 delete_handlers_for_content_reader_)) {
31415 return true;
31416 }
31417 }
31418 }
31419
31420 // Read content into `req.body`
31421 if (!read_content(strm, req, res)) { return false; }
31422 }
31423
31424 // Regular handler
31425 if (req.method == "GET" || req.method == "HEAD") {
31426 return dispatch_request(req, res, get_handlers_);
31427 } else if (req.method == "POST") {
31428 return dispatch_request(req, res, post_handlers_);
31429 } else if (req.method == "PUT") {
31430 return dispatch_request(req, res, put_handlers_);
31431 } else if (req.method == "DELETE") {
31432 return dispatch_request(req, res, delete_handlers_);
31433 } else if (req.method == "OPTIONS") {
31434 return dispatch_request(req, res, options_handlers_);
31435 } else if (req.method == "PATCH") {
31436 return dispatch_request(req, res, patch_handlers_);
31437 }
31438
31439 res.status = StatusCode::BadRequest_400;
31440 return false;
31441}
31442
31443inline bool Server::dispatch_request(Request &req, Response &res,
31444 const Handlers &handlers) const {
31445 for (const auto &x : handlers) {
31446 const auto &matcher = x.first;
31447 const auto &handler = x.second;
31448
31449 if (matcher->match(req)) {
31450 handler(req, res);
31451 return true;
31452 }
31453 }
31454 return false;
31455}
31456
31457inline void Server::apply_ranges(const Request &req, Response &res,
31458 std::string &content_type,
31459 std::string &boundary) const {
31460 if (req.ranges.size() > 1 && res.status == StatusCode::PartialContent_206) {
31461 auto it = res.headers.find("Content-Type");
31462 if (it != res.headers.end()) {
31463 content_type = it->second;
31464 res.headers.erase(it);
31465 }
31466
31467 boundary = detail::make_multipart_data_boundary();
31468
31469 res.set_header("Content-Type",
31470 "multipart/byteranges; boundary=" + boundary);
31471 }
31472
31473 auto type = detail::encoding_type(req, res);
31474
31475 if (res.body.empty()) {
31476 if (res.content_length_ > 0) {
31477 size_t length = 0;
31478 if (req.ranges.empty() || res.status != StatusCode::PartialContent_206) {
31479 length = res.content_length_;
31480 } else if (req.ranges.size() == 1) {
31481 auto offset_and_length = detail::get_range_offset_and_length(
31482 req.ranges[0], res.content_length_);
31483
31484 length = offset_and_length.second;
31485
31486 auto content_range = detail::make_content_range_header_field(
31487 offset_and_length, res.content_length_);
31488 res.set_header("Content-Range", content_range);
31489 } else {
31490 length = detail::get_multipart_ranges_data_length(
31491 req, boundary, content_type, res.content_length_);
31492 }
31493 res.set_header("Content-Length", std::to_string(length));
31494 } else {
31495 if (res.content_provider_) {
31496 if (res.is_chunked_content_provider_) {
31497 res.set_header("Transfer-Encoding", "chunked");
31498 if (type == detail::EncodingType::Gzip) {
31499 res.set_header("Content-Encoding", "gzip");
31500 } else if (type == detail::EncodingType::Brotli) {
31501 res.set_header("Content-Encoding", "br");
31502 }
31503 }
31504 }
31505 }
31506 } else {
31507 if (req.ranges.empty() || res.status != StatusCode::PartialContent_206) {
31508 ;
31509 } else if (req.ranges.size() == 1) {
31510 auto offset_and_length =
31511 detail::get_range_offset_and_length(req.ranges[0], res.body.size());
31512 auto offset = offset_and_length.first;
31513 auto length = offset_and_length.second;
31514
31515 auto content_range = detail::make_content_range_header_field(
31516 offset_and_length, res.body.size());
31517 res.set_header("Content-Range", content_range);
31518
31519 assert(offset + length <= res.body.size());
31520 res.body = res.body.substr(offset, length);
31521 } else {
31522 std::string data;
31523 detail::make_multipart_ranges_data(req, res, boundary, content_type,
31524 res.body.size(), data);
31525 res.body.swap(data);
31526 }
31527
31528 if (type != detail::EncodingType::None) {
31529 std::unique_ptr<detail::compressor> compressor;
31530 std::string content_encoding;
31531
31532 if (type == detail::EncodingType::Gzip) {
31533#ifdef CPPHTTPLIB_ZLIB_SUPPORT
31534 compressor = detail::make_unique<detail::gzip_compressor>();
31535 content_encoding = "gzip";
31536#endif
31537 } else if (type == detail::EncodingType::Brotli) {
31538#ifdef CPPHTTPLIB_BROTLI_SUPPORT
31539 compressor = detail::make_unique<detail::brotli_compressor>();
31540 content_encoding = "br";
31541#endif
31542 }
31543
31544 if (compressor) {
31545 std::string compressed;
31546 if (compressor->compress(res.body.data(), res.body.size(), true,
31547 [&](const char *data, size_t data_len) {
31548 compressed.append(data, data_len);
31549 return true;
31550 })) {
31551 res.body.swap(compressed);
31552 res.set_header("Content-Encoding", content_encoding);
31553 }
31554 }
31555 }
31556
31557 auto length = std::to_string(res.body.size());
31558 res.set_header("Content-Length", length);
31559 }
31560}
31561
31562inline bool Server::dispatch_request_for_content_reader(
31563 Request &req, Response &res, ContentReader content_reader,
31564 const HandlersForContentReader &handlers) const {
31565 for (const auto &x : handlers) {
31566 const auto &matcher = x.first;
31567 const auto &handler = x.second;
31568
31569 if (matcher->match(req)) {
31570 handler(req, res, content_reader);
31571 return true;
31572 }
31573 }
31574 return false;
31575}
31576
31577inline bool
31578Server::process_request(Stream &strm, bool close_connection,
31579 bool &connection_closed,
31580 const std::function<void(Request &)> &setup_request) {
31581 std::array<char, 2048> buf{};
31582
31583 detail::stream_line_reader line_reader(strm, buf.data(), buf.size());
31584
31585 // Connection has been closed on client
31586 if (!line_reader.getline()) { return false; }
31587
31588 Request req;
31589
31590 Response res;
31591 res.version = "HTTP/1.1";
31592 res.headers = default_headers_;
31593
31594#ifdef _WIN32
31595 // TODO: Increase FD_SETSIZE statically (libzmq), dynamically (MySQL).
31596#else
31597#ifndef CPPHTTPLIB_USE_POLL
31598 // Socket file descriptor exceeded FD_SETSIZE...
31599 if (strm.socket() >= FD_SETSIZE) {
31600 Headers dummy;
31601 detail::read_headers(strm, dummy);
31602 res.status = StatusCode::InternalServerError_500;
31603 return write_response(strm, close_connection, req, res);
31604 }
31605#endif
31606#endif
31607
31608 // Check if the request URI doesn't exceed the limit
31609 if (line_reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) {
31610 Headers dummy;
31611 detail::read_headers(strm, dummy);
31612 res.status = StatusCode::UriTooLong_414;
31613 return write_response(strm, close_connection, req, res);
31614 }
31615
31616 // Request line and headers
31617 if (!parse_request_line(line_reader.ptr(), req) ||
31618 !detail::read_headers(strm, req.headers)) {
31619 res.status = StatusCode::BadRequest_400;
31620 return write_response(strm, close_connection, req, res);
31621 }
31622
31623 if (req.get_header_value("Connection") == "close") {
31624 connection_closed = true;
31625 }
31626
31627 if (req.version == "HTTP/1.0" &&
31628 req.get_header_value("Connection") != "Keep-Alive") {
31629 connection_closed = true;
31630 }
31631
31632 strm.get_remote_ip_and_port(req.remote_addr, req.remote_port);
31633 req.set_header("REMOTE_ADDR", req.remote_addr);
31634 req.set_header("REMOTE_PORT", std::to_string(req.remote_port));
31635
31636 strm.get_local_ip_and_port(req.local_addr, req.local_port);
31637 req.set_header("LOCAL_ADDR", req.local_addr);
31638 req.set_header("LOCAL_PORT", std::to_string(req.local_port));
31639
31640 if (req.has_header("Range")) {
31641 const auto &range_header_value = req.get_header_value("Range");
31642 if (!detail::parse_range_header(range_header_value, req.ranges)) {
31643 res.status = StatusCode::RangeNotSatisfiable_416;
31644 return write_response(strm, close_connection, req, res);
31645 }
31646 }
31647
31648 if (setup_request) { setup_request(req); }
31649
31650 if (req.get_header_value("Expect") == "100-continue") {
31651 int status = StatusCode::Continue_100;
31652 if (expect_100_continue_handler_) {
31653 status = expect_100_continue_handler_(req, res);
31654 }
31655 switch (status) {
31656 case StatusCode::Continue_100:
31657 case StatusCode::ExpectationFailed_417:
31658 strm.write_format("HTTP/1.1 %d %s\r\n\r\n", status,
31659 status_message(status));
31660 break;
31661 default: return write_response(strm, close_connection, req, res);
31662 }
31663 }
31664
31665 // Routing
31666 auto routed = false;
31667#ifdef CPPHTTPLIB_NO_EXCEPTIONS
31668 routed = routing(req, res, strm);
31669#else
31670 try {
31671 routed = routing(req, res, strm);
31672 } catch (std::exception &e) {
31673 if (exception_handler_) {
31674 auto ep = std::current_exception();
31675 exception_handler_(req, res, ep);
31676 routed = true;
31677 } else {
31678 res.status = StatusCode::InternalServerError_500;
31679 std::string val;
31680 auto s = e.what();
31681 for (size_t i = 0; s[i]; i++) {
31682 switch (s[i]) {
31683 case '\r': val += "\\r"; break;
31684 case '\n': val += "\\n"; break;
31685 default: val += s[i]; break;
31686 }
31687 }
31688 res.set_header("EXCEPTION_WHAT", val);
31689 }
31690 } catch (...) {
31691 if (exception_handler_) {
31692 auto ep = std::current_exception();
31693 exception_handler_(req, res, ep);
31694 routed = true;
31695 } else {
31696 res.status = StatusCode::InternalServerError_500;
31697 res.set_header("EXCEPTION_WHAT", "UNKNOWN");
31698 }
31699 }
31700#endif
31701 if (routed) {
31702 if (res.status == -1) {
31703 res.status = req.ranges.empty() ? StatusCode::OK_200
31704 : StatusCode::PartialContent_206;
31705 }
31706
31707 if (detail::range_error(req, res)) {
31708 res.body.clear();
31709 res.content_length_ = 0;
31710 res.content_provider_ = nullptr;
31711 res.status = StatusCode::RangeNotSatisfiable_416;
31712 return write_response(strm, close_connection, req, res);
31713 }
31714
31715 return write_response_with_content(strm, close_connection, req, res);
31716 } else {
31717 if (res.status == -1) { res.status = StatusCode::NotFound_404; }
31718
31719 return write_response(strm, close_connection, req, res);
31720 }
31721}
31722
31723inline bool Server::is_valid() const { return true; }
31724
31725inline bool Server::process_and_close_socket(socket_t sock) {
31726 auto ret = detail::process_server_socket(
31727 svr_sock_, sock, keep_alive_max_count_, keep_alive_timeout_sec_,
31728 read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
31729 write_timeout_usec_,
31730 [this](Stream &strm, bool close_connection, bool &connection_closed) {
31731 return process_request(strm, close_connection, connection_closed,
31732 nullptr);
31733 });
31734
31735 detail::shutdown_socket(sock);
31736 detail::close_socket(sock);
31737 return ret;
31738}
31739
31740// HTTP client implementation
31741inline ClientImpl::ClientImpl(const std::string &host)
31742 : ClientImpl(host, 80, std::string(), std::string()) {}
31743
31744inline ClientImpl::ClientImpl(const std::string &host, int port)
31745 : ClientImpl(host, port, std::string(), std::string()) {}
31746
31747inline ClientImpl::ClientImpl(const std::string &host, int port,
31748 const std::string &client_cert_path,
31749 const std::string &client_key_path)
31750 : host_(host), port_(port),
31751 host_and_port_(adjust_host_string(host) + ":" + std::to_string(port)),
31752 client_cert_path_(client_cert_path), client_key_path_(client_key_path) {}
31753
31754inline ClientImpl::~ClientImpl() {
31755 std::lock_guard<std::mutex> guard(socket_mutex_);
31756 shutdown_socket(socket_);
31757 close_socket(socket_);
31758}
31759
31760inline bool ClientImpl::is_valid() const { return true; }
31761
31762inline void ClientImpl::copy_settings(const ClientImpl &rhs) {
31763 client_cert_path_ = rhs.client_cert_path_;
31764 client_key_path_ = rhs.client_key_path_;
31765 connection_timeout_sec_ = rhs.connection_timeout_sec_;
31766 read_timeout_sec_ = rhs.read_timeout_sec_;
31767 read_timeout_usec_ = rhs.read_timeout_usec_;
31768 write_timeout_sec_ = rhs.write_timeout_sec_;
31769 write_timeout_usec_ = rhs.write_timeout_usec_;
31770 basic_auth_username_ = rhs.basic_auth_username_;
31771 basic_auth_password_ = rhs.basic_auth_password_;
31772 bearer_token_auth_token_ = rhs.bearer_token_auth_token_;
31773#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
31774 digest_auth_username_ = rhs.digest_auth_username_;
31775 digest_auth_password_ = rhs.digest_auth_password_;
31776#endif
31777 keep_alive_ = rhs.keep_alive_;
31778 follow_location_ = rhs.follow_location_;
31779 url_encode_ = rhs.url_encode_;
31780 address_family_ = rhs.address_family_;
31781 tcp_nodelay_ = rhs.tcp_nodelay_;
31782 socket_options_ = rhs.socket_options_;
31783 compress_ = rhs.compress_;
31784 decompress_ = rhs.decompress_;
31785 interface_ = rhs.interface_;
31786 proxy_host_ = rhs.proxy_host_;
31787 proxy_port_ = rhs.proxy_port_;
31788 proxy_basic_auth_username_ = rhs.proxy_basic_auth_username_;
31789 proxy_basic_auth_password_ = rhs.proxy_basic_auth_password_;
31790 proxy_bearer_token_auth_token_ = rhs.proxy_bearer_token_auth_token_;
31791#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
31792 proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_;
31793 proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_;
31794#endif
31795#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
31796 ca_cert_file_path_ = rhs.ca_cert_file_path_;
31797 ca_cert_dir_path_ = rhs.ca_cert_dir_path_;
31798 ca_cert_store_ = rhs.ca_cert_store_;
31799#endif
31800#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
31801 server_certificate_verification_ = rhs.server_certificate_verification_;
31802#endif
31803 logger_ = rhs.logger_;
31804}
31805
31806inline socket_t ClientImpl::create_client_socket(Error &error) const {
31807 if (!proxy_host_.empty() && proxy_port_ != -1) {
31808 return detail::create_client_socket(
31809 proxy_host_, std::string(), proxy_port_, address_family_, tcp_nodelay_,
31810 socket_options_, connection_timeout_sec_, connection_timeout_usec_,
31811 read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
31812 write_timeout_usec_, interface_, error);
31813 }
31814
31815 // Check is custom IP specified for host_
31816 std::string ip;
31817 auto it = addr_map_.find(host_);
31818 if (it != addr_map_.end()) { ip = it->second; }
31819
31820 return detail::create_client_socket(
31821 host_, ip, port_, address_family_, tcp_nodelay_, socket_options_,
31822 connection_timeout_sec_, connection_timeout_usec_, read_timeout_sec_,
31823 read_timeout_usec_, write_timeout_sec_, write_timeout_usec_, interface_,
31824 error);
31825}
31826
31827inline bool ClientImpl::create_and_connect_socket(Socket &socket,
31828 Error &error) {
31829 auto sock = create_client_socket(error);
31830 if (sock == INVALID_SOCKET) { return false; }
31831 socket.sock = sock;
31832 return true;
31833}
31834
31835inline void ClientImpl::shutdown_ssl(Socket & /*socket*/,
31836 bool /*shutdown_gracefully*/) {
31837 // If there are any requests in flight from threads other than us, then it's
31838 // a thread-unsafe race because individual ssl* objects are not thread-safe.
31839 assert(socket_requests_in_flight_ == 0 ||
31840 socket_requests_are_from_thread_ == std::this_thread::get_id());
31841}
31842
31843inline void ClientImpl::shutdown_socket(Socket &socket) const {
31844 if (socket.sock == INVALID_SOCKET) { return; }
31845 detail::shutdown_socket(socket.sock);
31846}
31847
31848inline void ClientImpl::close_socket(Socket &socket) {
31849 // If there are requests in flight in another thread, usually closing
31850 // the socket will be fine and they will simply receive an error when
31851 // using the closed socket, but it is still a bug since rarely the OS
31852 // may reassign the socket id to be used for a new socket, and then
31853 // suddenly they will be operating on a live socket that is different
31854 // than the one they intended!
31855 assert(socket_requests_in_flight_ == 0 ||
31856 socket_requests_are_from_thread_ == std::this_thread::get_id());
31857
31858 // It is also a bug if this happens while SSL is still active
31859#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
31860 assert(socket.ssl == nullptr);
31861#endif
31862 if (socket.sock == INVALID_SOCKET) { return; }
31863 detail::close_socket(socket.sock);
31864 socket.sock = INVALID_SOCKET;
31865}
31866
31867inline bool ClientImpl::read_response_line(Stream &strm, const Request &req,
31868 Response &res) const {
31869 std::array<char, 2048> buf{};
31870
31871 detail::stream_line_reader line_reader(strm, buf.data(), buf.size());
31872
31873 if (!line_reader.getline()) { return false; }
31874
31875#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
31876 const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n");
31877#else
31878 const static std::regex re("(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
31879#endif
31880
31881 std::cmatch m;
31882 if (!std::regex_match(line_reader.ptr(), m, re)) {
31883 return req.method == "CONNECT";
31884 }
31885 res.version = std::string(m[1]);
31886 res.status = std::stoi(std::string(m[2]));
31887 res.reason = std::string(m[3]);
31888
31889 // Ignore '100 Continue'
31890 while (res.status == StatusCode::Continue_100) {
31891 if (!line_reader.getline()) { return false; } // CRLF
31892 if (!line_reader.getline()) { return false; } // next response line
31893
31894 if (!std::regex_match(line_reader.ptr(), m, re)) { return false; }
31895 res.version = std::string(m[1]);
31896 res.status = std::stoi(std::string(m[2]));
31897 res.reason = std::string(m[3]);
31898 }
31899
31900 return true;
31901}
31902
31903inline bool ClientImpl::send(Request &req, Response &res, Error &error) {
31904 std::lock_guard<std::recursive_mutex> request_mutex_guard(request_mutex_);
31905 auto ret = send_(req, res, error);
31906 if (error == Error::SSLPeerCouldBeClosed_) {
31907 assert(!ret);
31908 ret = send_(req, res, error);
31909 }
31910 return ret;
31911}
31912
31913inline bool ClientImpl::send_(Request &req, Response &res, Error &error) {
31914 {
31915 std::lock_guard<std::mutex> guard(socket_mutex_);
31916
31917 // Set this to false immediately - if it ever gets set to true by the end of
31918 // the request, we know another thread instructed us to close the socket.
31919 socket_should_be_closed_when_request_is_done_ = false;
31920
31921 auto is_alive = false;
31922 if (socket_.is_open()) {
31923 is_alive = detail::is_socket_alive(socket_.sock);
31924 if (!is_alive) {
31925 // Attempt to avoid sigpipe by shutting down nongracefully if it seems
31926 // like the other side has already closed the connection Also, there
31927 // cannot be any requests in flight from other threads since we locked
31928 // request_mutex_, so safe to close everything immediately
31929 const bool shutdown_gracefully = false;
31930 shutdown_ssl(socket_, shutdown_gracefully);
31931 shutdown_socket(socket_);
31932 close_socket(socket_);
31933 }
31934 }
31935
31936 if (!is_alive) {
31937 if (!create_and_connect_socket(socket_, error)) { return false; }
31938
31939#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
31940 // TODO: refactoring
31941 if (is_ssl()) {
31942 auto &scli = static_cast<SSLClient &>(*this);
31943 if (!proxy_host_.empty() && proxy_port_ != -1) {
31944 auto success = false;
31945 if (!scli.connect_with_proxy(socket_, res, success, error)) {
31946 return success;
31947 }
31948 }
31949
31950 if (!scli.initialize_ssl(socket_, error)) { return false; }
31951 }
31952#endif
31953 }
31954
31955 // Mark the current socket as being in use so that it cannot be closed by
31956 // anyone else while this request is ongoing, even though we will be
31957 // releasing the mutex.
31958 if (socket_requests_in_flight_ > 1) {
31959 assert(socket_requests_are_from_thread_ == std::this_thread::get_id());
31960 }
31961 socket_requests_in_flight_ += 1;
31962 socket_requests_are_from_thread_ = std::this_thread::get_id();
31963 }
31964
31965 for (const auto &header : default_headers_) {
31966 if (req.headers.find(header.first) == req.headers.end()) {
31967 req.headers.insert(header);
31968 }
31969 }
31970
31971 auto ret = false;
31972 auto close_connection = !keep_alive_;
31973
31974 auto se = detail::scope_exit([&]() {
31975 // Briefly lock mutex in order to mark that a request is no longer ongoing
31976 std::lock_guard<std::mutex> guard(socket_mutex_);
31977 socket_requests_in_flight_ -= 1;
31978 if (socket_requests_in_flight_ <= 0) {
31979 assert(socket_requests_in_flight_ == 0);
31980 socket_requests_are_from_thread_ = std::thread::id();
31981 }
31982
31983 if (socket_should_be_closed_when_request_is_done_ || close_connection ||
31984 !ret) {
31985 shutdown_ssl(socket_, true);
31986 shutdown_socket(socket_);
31987 close_socket(socket_);
31988 }
31989 });
31990
31991 ret = process_socket(socket_, [&](Stream &strm) {
31992 return handle_request(strm, req, res, close_connection, error);
31993 });
31994
31995 if (!ret) {
31996 if (error == Error::Success) { error = Error::Unknown; }
31997 }
31998
31999 return ret;
32000}
32001
32002inline Result ClientImpl::send(const Request &req) {
32003 auto req2 = req;
32004 return send_(std::move(req2));
32005}
32006
32007inline Result ClientImpl::send_(Request &&req) {
32008 auto res = detail::make_unique<Response>();
32009 auto error = Error::Success;
32010 auto ret = send(req, *res, error);
32011 return Result{ret ? std::move(res) : nullptr, error, std::move(req.headers)};
32012}
32013
32014inline bool ClientImpl::handle_request(Stream &strm, Request &req,
32015 Response &res, bool close_connection,
32016 Error &error) {
32017 if (req.path.empty()) {
32018 error = Error::Connection;
32019 return false;
32020 }
32021
32022 auto req_save = req;
32023
32024 bool ret;
32025
32026 if (!is_ssl() && !proxy_host_.empty() && proxy_port_ != -1) {
32027 auto req2 = req;
32028 req2.path = "http://" + host_and_port_ + req.path;
32029 ret = process_request(strm, req2, res, close_connection, error);
32030 req = req2;
32031 req.path = req_save.path;
32032 } else {
32033 ret = process_request(strm, req, res, close_connection, error);
32034 }
32035
32036 if (!ret) { return false; }
32037
32038 if (res.get_header_value("Connection") == "close" ||
32039 (res.version == "HTTP/1.0" && res.reason != "Connection established")) {
32040 // TODO this requires a not-entirely-obvious chain of calls to be correct
32041 // for this to be safe.
32042
32043 // This is safe to call because handle_request is only called by send_
32044 // which locks the request mutex during the process. It would be a bug
32045 // to call it from a different thread since it's a thread-safety issue
32046 // to do these things to the socket if another thread is using the socket.
32047 std::lock_guard<std::mutex> guard(socket_mutex_);
32048 shutdown_ssl(socket_, true);
32049 shutdown_socket(socket_);
32050 close_socket(socket_);
32051 }
32052
32053 if (300 < res.status && res.status < 400 && follow_location_) {
32054 req = req_save;
32055 ret = redirect(req, res, error);
32056 }
32057
32058#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
32059 if ((res.status == StatusCode::Unauthorized_401 ||
32060 res.status == StatusCode::ProxyAuthenticationRequired_407) &&
32061 req.authorization_count_ < 5) {
32062 auto is_proxy = res.status == StatusCode::ProxyAuthenticationRequired_407;
32063 const auto &username =
32064 is_proxy ? proxy_digest_auth_username_ : digest_auth_username_;
32065 const auto &password =
32066 is_proxy ? proxy_digest_auth_password_ : digest_auth_password_;
32067
32068 if (!username.empty() && !password.empty()) {
32069 std::map<std::string, std::string> auth;
32070 if (detail::parse_www_authenticate(res, auth, is_proxy)) {
32071 Request new_req = req;
32072 new_req.authorization_count_ += 1;
32073 new_req.headers.erase(is_proxy ? "Proxy-Authorization"
32074 : "Authorization");
32075 new_req.headers.insert(detail::make_digest_authentication_header(
32076 req, auth, new_req.authorization_count_, detail::random_string(10),
32077 username, password, is_proxy));
32078
32079 Response new_res;
32080
32081 ret = send(new_req, new_res, error);
32082 if (ret) { res = new_res; }
32083 }
32084 }
32085 }
32086#endif
32087
32088 return ret;
32089}
32090
32091inline bool ClientImpl::redirect(Request &req, Response &res, Error &error) {
32092 if (req.redirect_count_ == 0) {
32093 error = Error::ExceedRedirectCount;
32094 return false;
32095 }
32096
32097 auto location = res.get_header_value("location");
32098 if (location.empty()) { return false; }
32099
32100 const static std::regex re(
32101 R"((?:(https?):)?(?://(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)");
32102
32103 std::smatch m;
32104 if (!std::regex_match(location, m, re)) { return false; }
32105
32106 auto scheme = is_ssl() ? "https" : "http";
32107
32108 auto next_scheme = m[1].str();
32109 auto next_host = m[2].str();
32110 if (next_host.empty()) { next_host = m[3].str(); }
32111 auto port_str = m[4].str();
32112 auto next_path = m[5].str();
32113 auto next_query = m[6].str();
32114
32115 auto next_port = port_;
32116 if (!port_str.empty()) {
32117 next_port = std::stoi(port_str);
32118 } else if (!next_scheme.empty()) {
32119 next_port = next_scheme == "https" ? 443 : 80;
32120 }
32121
32122 if (next_scheme.empty()) { next_scheme = scheme; }
32123 if (next_host.empty()) { next_host = host_; }
32124 if (next_path.empty()) { next_path = "/"; }
32125
32126 auto path = detail::decode_url(next_path, true) + next_query;
32127
32128 if (next_scheme == scheme && next_host == host_ && next_port == port_) {
32129 return detail::redirect(*this, req, res, path, location, error);
32130 } else {
32131 if (next_scheme == "https") {
32132#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
32133 SSLClient cli(next_host, next_port);
32134 cli.copy_settings(*this);
32135 if (ca_cert_store_) { cli.set_ca_cert_store(ca_cert_store_); }
32136 return detail::redirect(cli, req, res, path, location, error);
32137#else
32138 return false;
32139#endif
32140 } else {
32141 ClientImpl cli(next_host, next_port);
32142 cli.copy_settings(*this);
32143 return detail::redirect(cli, req, res, path, location, error);
32144 }
32145 }
32146}
32147
32148inline bool ClientImpl::write_content_with_provider(Stream &strm,
32149 const Request &req,
32150 Error &error) const {
32151 auto is_shutting_down = []() { return false; };
32152
32153 if (req.is_chunked_content_provider_) {
32154 // TODO: Brotli support
32155 std::unique_ptr<detail::compressor> compressor;
32156#ifdef CPPHTTPLIB_ZLIB_SUPPORT
32157 if (compress_) {
32158 compressor = detail::make_unique<detail::gzip_compressor>();
32159 } else
32160#endif
32161 {
32162 compressor = detail::make_unique<detail::nocompressor>();
32163 }
32164
32165 return detail::write_content_chunked(strm, req.content_provider_,
32166 is_shutting_down, *compressor, error);
32167 } else {
32168 return detail::write_content(strm, req.content_provider_, 0,
32169 req.content_length_, is_shutting_down, error);
32170 }
32171}
32172
32173inline bool ClientImpl::write_request(Stream &strm, Request &req,
32174 bool close_connection, Error &error) {
32175 // Prepare additional headers
32176 if (close_connection) {
32177 if (!req.has_header("Connection")) {
32178 req.set_header("Connection", "close");
32179 }
32180 }
32181
32182 if (!req.has_header("Host")) {
32183 if (is_ssl()) {
32184 if (port_ == 443) {
32185 req.set_header("Host", host_);
32186 } else {
32187 req.set_header("Host", host_and_port_);
32188 }
32189 } else {
32190 if (port_ == 80) {
32191 req.set_header("Host", host_);
32192 } else {
32193 req.set_header("Host", host_and_port_);
32194 }
32195 }
32196 }
32197
32198 if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); }
32199
32200#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT
32201 if (!req.has_header("User-Agent")) {
32202 auto agent = std::string("cpp-httplib/") + CPPHTTPLIB_VERSION;
32203 req.set_header("User-Agent", agent);
32204 }
32205#endif
32206
32207 if (req.body.empty()) {
32208 if (req.content_provider_) {
32209 if (!req.is_chunked_content_provider_) {
32210 if (!req.has_header("Content-Length")) {
32211 auto length = std::to_string(req.content_length_);
32212 req.set_header("Content-Length", length);
32213 }
32214 }
32215 } else {
32216 if (req.method == "POST" || req.method == "PUT" ||
32217 req.method == "PATCH") {
32218 req.set_header("Content-Length", "0");
32219 }
32220 }
32221 } else {
32222 if (!req.has_header("Content-Type")) {
32223 req.set_header("Content-Type", "text/plain");
32224 }
32225
32226 if (!req.has_header("Content-Length")) {
32227 auto length = std::to_string(req.body.size());
32228 req.set_header("Content-Length", length);
32229 }
32230 }
32231
32232 if (!basic_auth_password_.empty() || !basic_auth_username_.empty()) {
32233 if (!req.has_header("Authorization")) {
32234 req.headers.insert(make_basic_authentication_header(
32235 basic_auth_username_, basic_auth_password_, false));
32236 }
32237 }
32238
32239 if (!proxy_basic_auth_username_.empty() &&
32240 !proxy_basic_auth_password_.empty()) {
32241 if (!req.has_header("Proxy-Authorization")) {
32242 req.headers.insert(make_basic_authentication_header(
32243 proxy_basic_auth_username_, proxy_basic_auth_password_, true));
32244 }
32245 }
32246
32247 if (!bearer_token_auth_token_.empty()) {
32248 if (!req.has_header("Authorization")) {
32249 req.headers.insert(make_bearer_token_authentication_header(
32250 bearer_token_auth_token_, false));
32251 }
32252 }
32253
32254 if (!proxy_bearer_token_auth_token_.empty()) {
32255 if (!req.has_header("Proxy-Authorization")) {
32256 req.headers.insert(make_bearer_token_authentication_header(
32257 proxy_bearer_token_auth_token_, true));
32258 }
32259 }
32260
32261 // Request line and headers
32262 {
32263 detail::BufferStream bstrm;
32264
32265 const auto &path = url_encode_ ? detail::encode_url(req.path) : req.path;
32266 bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str());
32267
32268 header_writer_(bstrm, req.headers);
32269
32270 // Flush buffer
32271 auto &data = bstrm.get_buffer();
32272 if (!detail::write_data(strm, data.data(), data.size())) {
32273 error = Error::Write;
32274 return false;
32275 }
32276 }
32277
32278 // Body
32279 if (req.body.empty()) {
32280 return write_content_with_provider(strm, req, error);
32281 }
32282
32283 if (!detail::write_data(strm, req.body.data(), req.body.size())) {
32284 error = Error::Write;
32285 return false;
32286 }
32287
32288 return true;
32289}
32290
32291inline std::unique_ptr<Response> ClientImpl::send_with_content_provider(
32292 Request &req, const char *body, size_t content_length,
32293 ContentProvider content_provider,
32294 ContentProviderWithoutLength content_provider_without_length,
32295 const std::string &content_type, Error &error, ContentReceiver content_receiver) {
32296 if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
32297
32298#ifdef CPPHTTPLIB_ZLIB_SUPPORT
32299 if (compress_) { req.set_header("Content-Encoding", "gzip"); }
32300#endif
32301
32302#ifdef CPPHTTPLIB_ZLIB_SUPPORT
32303 if (compress_ && !content_provider_without_length) {
32304 // TODO: Brotli support
32305 detail::gzip_compressor compressor;
32306
32307 if (content_provider) {
32308 auto ok = true;
32309 size_t offset = 0;
32310 DataSink data_sink;
32311
32312 data_sink.write = [&](const char *data, size_t data_len) -> bool {
32313 if (ok) {
32314 auto last = offset + data_len == content_length;
32315
32316 auto ret = compressor.compress(
32317 data, data_len, last,
32318 [&](const char *compressed_data, size_t compressed_data_len) {
32319 req.body.append(compressed_data, compressed_data_len);
32320 return true;
32321 });
32322
32323 if (ret) {
32324 offset += data_len;
32325 } else {
32326 ok = false;
32327 }
32328 }
32329 return ok;
32330 };
32331
32332 while (ok && offset < content_length) {
32333 if (!content_provider(offset, content_length - offset, data_sink)) {
32334 error = Error::Canceled;
32335 return nullptr;
32336 }
32337 }
32338 } else {
32339 if (!compressor.compress(body, content_length, true,
32340 [&](const char *data, size_t data_len) {
32341 req.body.append(data, data_len);
32342 return true;
32343 })) {
32344 error = Error::Compression;
32345 return nullptr;
32346 }
32347 }
32348 } else
32349#endif
32350 {
32351 if (content_provider) {
32352 req.content_length_ = content_length;
32353 req.content_provider_ = std::move(content_provider);
32354 req.is_chunked_content_provider_ = false;
32355 } else if (content_provider_without_length) {
32356 req.content_length_ = 0;
32357 req.content_provider_ = detail::ContentProviderAdapter(
32358 std::move(content_provider_without_length));
32359 req.is_chunked_content_provider_ = true;
32360 req.set_header("Transfer-Encoding", "chunked");
32361 } else {
32362 req.body.assign(body, content_length);
32363 }
32364 }
32365
32366 req.response_handler = std::move(nullptr);
32367 if (content_receiver) req.content_receiver =
32368 [content_receiver](const char *data, size_t data_length,
32369 uint64_t /*offset*/, uint64_t /*total_length*/) {
32370 return content_receiver(data, data_length);
32371 };
32372
32373 auto res = detail::make_unique<Response>();
32374 return send(req, *res, error) ? std::move(res) : nullptr;
32375}
32376
32377inline Result ClientImpl::send_with_content_provider(
32378 const std::string &method, const std::string &path, const Headers &headers,
32379 const char *body, size_t content_length, ContentProvider content_provider,
32380 ContentProviderWithoutLength content_provider_without_length,
32381 const std::string &content_type, Progress progress, ContentReceiver content_receiver) {
32382 Request req;
32383 req.method = method;
32384 req.headers = headers;
32385 req.path = path;
32386 req.progress = progress;
32387
32388 auto error = Error::Success;
32389
32390 auto res = send_with_content_provider(
32391 req, body, content_length, std::move(content_provider),
32392 std::move(content_provider_without_length), content_type, error, std::move(content_receiver));
32393
32394 return Result{std::move(res), error, std::move(req.headers)};
32395}
32396
32397inline std::string
32398ClientImpl::adjust_host_string(const std::string &host) const {
32399 if (host.find(':') != std::string::npos) { return "[" + host + "]"; }
32400 return host;
32401}
32402
32403inline bool ClientImpl::process_request(Stream &strm, Request &req,
32404 Response &res, bool close_connection,
32405 Error &error) {
32406 // Send request
32407 if (!write_request(strm, req, close_connection, error)) { return false; }
32408
32409#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
32410 if (is_ssl()) {
32411 auto is_proxy_enabled = !proxy_host_.empty() && proxy_port_ != -1;
32412 if (!is_proxy_enabled) {
32413 char buf[1];
32414 if (SSL_peek(socket_.ssl, buf, 1) == 0 &&
32415 SSL_get_error(socket_.ssl, 0) == SSL_ERROR_ZERO_RETURN) {
32416 error = Error::SSLPeerCouldBeClosed_;
32417 return false;
32418 }
32419 }
32420 }
32421#endif
32422
32423 // Receive response and headers
32424 if (!read_response_line(strm, req, res) ||
32425 !detail::read_headers(strm, res.headers)) {
32426 error = Error::Read;
32427 return false;
32428 }
32429
32430 // Body
32431 if ((res.status != StatusCode::NoContent_204) && req.method != "HEAD" &&
32432 req.method != "CONNECT") {
32433 auto redirect = 300 < res.status && res.status < 400 && follow_location_;
32434
32435 if (req.response_handler && !redirect) {
32436 if (!req.response_handler(res)) {
32437 error = Error::Canceled;
32438 return false;
32439 }
32440 }
32441
32442 auto out =
32443 req.content_receiver
32444 ? static_cast<ContentReceiverWithProgress>(
32445 [&](const char *buf, size_t n, uint64_t off, uint64_t len) {
32446 if (redirect) { return true; }
32447 auto ret = req.content_receiver(buf, n, off, len);
32448 if (!ret) { error = Error::Canceled; }
32449 return ret;
32450 })
32451 : static_cast<ContentReceiverWithProgress>(
32452 [&](const char *buf, size_t n, uint64_t /*off*/,
32453 uint64_t /*len*/) {
32454 if (res.body.size() + n > res.body.max_size()) {
32455 return false;
32456 }
32457 res.body.append(buf, n);
32458 return true;
32459 });
32460
32461 auto progress = [&](uint64_t current, uint64_t total) {
32462 if (!req.progress || redirect) { return true; }
32463 auto ret = req.progress(current, total);
32464 if (!ret) { error = Error::Canceled; }
32465 return ret;
32466 };
32467
32468 int dummy_status;
32469 if (!detail::read_content(strm, res, (std::numeric_limits<size_t>::max)(),
32470 dummy_status, std::move(progress), std::move(out),
32471 decompress_)) {
32472 if (error != Error::Canceled) { error = Error::Read; }
32473 return false;
32474 }
32475 }
32476
32477 // Log
32478 if (logger_) { logger_(req, res); }
32479
32480 return true;
32481}
32482
32483inline ContentProviderWithoutLength ClientImpl::get_multipart_content_provider(
32484 const std::string &boundary, const MultipartFormDataItems &items,
32485 const MultipartFormDataProviderItems &provider_items) const {
32486 size_t cur_item = 0;
32487 size_t cur_start = 0;
32488 // cur_item and cur_start are copied to within the std::function and maintain
32489 // state between successive calls
32490 return [&, cur_item, cur_start](size_t offset,
32491 DataSink &sink) mutable -> bool {
32492 if (!offset && !items.empty()) {
32493 sink.os << detail::serialize_multipart_formdata(items, boundary, false);
32494 return true;
32495 } else if (cur_item < provider_items.size()) {
32496 if (!cur_start) {
32497 const auto &begin = detail::serialize_multipart_formdata_item_begin(
32498 provider_items[cur_item], boundary);
32499 offset += begin.size();
32500 cur_start = offset;
32501 sink.os << begin;
32502 }
32503
32504 DataSink cur_sink;
32505 auto has_data = true;
32506 cur_sink.write = sink.write;
32507 cur_sink.done = [&]() { has_data = false; };
32508
32509 if (!provider_items[cur_item].provider(offset - cur_start, cur_sink)) {
32510 return false;
32511 }
32512
32513 if (!has_data) {
32514 sink.os << detail::serialize_multipart_formdata_item_end();
32515 cur_item++;
32516 cur_start = 0;
32517 }
32518 return true;
32519 } else {
32520 sink.os << detail::serialize_multipart_formdata_finish(boundary);
32521 sink.done();
32522 return true;
32523 }
32524 };
32525}
32526
32527inline bool
32528ClientImpl::process_socket(const Socket &socket,
32529 std::function<bool(Stream &strm)> callback) {
32530 return detail::process_client_socket(
32531 socket.sock, read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
32532 write_timeout_usec_, std::move(callback));
32533}
32534
32535inline bool ClientImpl::is_ssl() const { return false; }
32536
32537inline Result ClientImpl::Get(const std::string &path) {
32538 return Get(path, Headers(), Progress());
32539}
32540
32541inline Result ClientImpl::Get(const std::string &path, Progress progress) {
32542 return Get(path, Headers(), std::move(progress));
32543}
32544
32545inline Result ClientImpl::Get(const std::string &path, const Headers &headers) {
32546 return Get(path, headers, Progress());
32547}
32548
32549inline Result ClientImpl::Get(const std::string &path, const Headers &headers,
32550 Progress progress) {
32551 Request req;
32552 req.method = "GET";
32553 req.path = path;
32554 req.headers = headers;
32555 req.progress = std::move(progress);
32556
32557 return send_(std::move(req));
32558}
32559
32560inline Result ClientImpl::Get(const std::string &path,
32561 ContentReceiver content_receiver) {
32562 return Get(path, Headers(), nullptr, std::move(content_receiver), nullptr);
32563}
32564
32565inline Result ClientImpl::Get(const std::string &path,
32566 ContentReceiver content_receiver,
32567 Progress progress) {
32568 return Get(path, Headers(), nullptr, std::move(content_receiver),
32569 std::move(progress));
32570}
32571
32572inline Result ClientImpl::Get(const std::string &path, const Headers &headers,
32573 ContentReceiver content_receiver) {
32574 return Get(path, headers, nullptr, std::move(content_receiver), nullptr);
32575}
32576
32577inline Result ClientImpl::Get(const std::string &path, const Headers &headers,
32578 ContentReceiver content_receiver,
32579 Progress progress) {
32580 return Get(path, headers, nullptr, std::move(content_receiver),
32581 std::move(progress));
32582}
32583
32584inline Result ClientImpl::Get(const std::string &path,
32585 ResponseHandler response_handler,
32586 ContentReceiver content_receiver) {
32587 return Get(path, Headers(), std::move(response_handler),
32588 std::move(content_receiver), nullptr);
32589}
32590
32591inline Result ClientImpl::Get(const std::string &path, const Headers &headers,
32592 ResponseHandler response_handler,
32593 ContentReceiver content_receiver) {
32594 return Get(path, headers, std::move(response_handler),
32595 std::move(content_receiver), nullptr);
32596}
32597
32598inline Result ClientImpl::Get(const std::string &path,
32599 ResponseHandler response_handler,
32600 ContentReceiver content_receiver,
32601 Progress progress) {
32602 return Get(path, Headers(), std::move(response_handler),
32603 std::move(content_receiver), std::move(progress));
32604}
32605
32606inline Result ClientImpl::Get(const std::string &path, const Headers &headers,
32607 ResponseHandler response_handler,
32608 ContentReceiver content_receiver,
32609 Progress progress) {
32610 Request req;
32611 req.method = "GET";
32612 req.path = path;
32613 req.headers = headers;
32614 req.response_handler = std::move(response_handler);
32615 req.content_receiver =
32616 [content_receiver](const char *data, size_t data_length,
32617 uint64_t /*offset*/, uint64_t /*total_length*/) {
32618 return content_receiver(data, data_length);
32619 };
32620 req.progress = std::move(progress);
32621
32622 return send_(std::move(req));
32623}
32624
32625inline Result ClientImpl::Get(const std::string &path, const Params &params,
32626 const Headers &headers, Progress progress) {
32627 if (params.empty()) { return Get(path, headers); }
32628
32629 std::string path_with_query = append_query_params(path, params);
32630 return Get(path_with_query, headers, std::move(progress));
32631}
32632
32633inline Result ClientImpl::Get(const std::string &path, const Params &params,
32634 const Headers &headers,
32635 ContentReceiver content_receiver,
32636 Progress progress) {
32637 return Get(path, params, headers, nullptr, std::move(content_receiver),
32638 std::move(progress));
32639}
32640
32641inline Result ClientImpl::Get(const std::string &path, const Params &params,
32642 const Headers &headers,
32643 ResponseHandler response_handler,
32644 ContentReceiver content_receiver,
32645 Progress progress) {
32646 if (params.empty()) {
32647 return Get(path, headers, std::move(response_handler),
32648 std::move(content_receiver), std::move(progress));
32649 }
32650
32651 std::string path_with_query = append_query_params(path, params);
32652 return Get(path_with_query, headers, std::move(response_handler),
32653 std::move(content_receiver), std::move(progress));
32654}
32655
32656inline Result ClientImpl::Head(const std::string &path) {
32657 return Head(path, Headers());
32658}
32659
32660inline Result ClientImpl::Head(const std::string &path,
32661 const Headers &headers) {
32662 Request req;
32663 req.method = "HEAD";
32664 req.headers = headers;
32665 req.path = path;
32666
32667 return send_(std::move(req));
32668}
32669
32670inline Result ClientImpl::Post(const std::string &path) {
32671 return Post(path, std::string(), std::string());
32672}
32673
32674inline Result ClientImpl::Post(const std::string &path,
32675 const Headers &headers) {
32676 return Post(path, headers, nullptr, 0, std::string());
32677}
32678
32679inline Result ClientImpl::Post(const std::string &path, const char *body,
32680 size_t content_length,
32681 const std::string &content_type) {
32682 return Post(path, Headers(), body, content_length, content_type, nullptr);
32683}
32684
32685inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
32686 const char *body, size_t content_length,
32687 const std::string &content_type) {
32688 return send_with_content_provider("POST", path, headers, body, content_length,
32689 nullptr, nullptr, content_type, nullptr);
32690}
32691
32692inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
32693 const char *body, size_t content_length,
32694 const std::string &content_type,
32695 Progress progress) {
32696 return send_with_content_provider("POST", path, headers, body, content_length,
32697 nullptr, nullptr, content_type, progress);
32698}
32699
32700inline Result ClientImpl::Post(const std::string &path, const std::string &body,
32701 const std::string &content_type) {
32702 return Post(path, Headers(), body, content_type);
32703}
32704
32705inline Result ClientImpl::Post(const std::string &path, const std::string &body,
32706 const std::string &content_type, ContentReceiver content_receiver) {
32707 return Post(path, Headers(), body, content_type, std::move(content_receiver));
32708}
32709
32710inline Result ClientImpl::Post(const std::string &path, const std::string &body,
32711 const std::string &content_type,
32712 Progress progress) {
32713 return Post(path, Headers(), body, content_type, progress);
32714}
32715
32716inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
32717 const std::string &body,
32718 const std::string &content_type
32719 ) {
32720 return send_with_content_provider("POST", path, headers, body.data(),
32721 body.size(), nullptr, nullptr, content_type,
32722 nullptr, nullptr);
32723}
32724
32725inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
32726 const std::string &body,
32727 const std::string &content_type,
32728 ContentReceiver content_receiver) {
32729 return send_with_content_provider("POST", path, headers, body.data(),
32730 body.size(), nullptr, nullptr, content_type,
32731 nullptr, std::move(content_receiver));
32732}
32733
32734
32735inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
32736 const std::string &body,
32737 const std::string &content_type,
32738 Progress progress) {
32739 return send_with_content_provider("POST", path, headers, body.data(),
32740 body.size(), nullptr, nullptr, content_type,
32741 progress);
32742}
32743
32744inline Result ClientImpl::Post(const std::string &path, const Params &params) {
32745 return Post(path, Headers(), params);
32746}
32747
32748inline Result ClientImpl::Post(const std::string &path, size_t content_length,
32749 ContentProvider content_provider,
32750 const std::string &content_type) {
32751 return Post(path, Headers(), content_length, std::move(content_provider),
32752 content_type);
32753}
32754
32755inline Result ClientImpl::Post(const std::string &path,
32756 ContentProviderWithoutLength content_provider,
32757 const std::string &content_type) {
32758 return Post(path, Headers(), std::move(content_provider), content_type);
32759}
32760
32761inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
32762 size_t content_length,
32763 ContentProvider content_provider,
32764 const std::string &content_type) {
32765 return send_with_content_provider("POST", path, headers, nullptr,
32766 content_length, std::move(content_provider),
32767 nullptr, content_type, nullptr);
32768}
32769
32770inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
32771 ContentProviderWithoutLength content_provider,
32772 const std::string &content_type) {
32773 return send_with_content_provider("POST", path, headers, nullptr, 0, nullptr,
32774 std::move(content_provider), content_type,
32775 nullptr);
32776}
32777
32778inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
32779 const Params &params) {
32780 auto query = detail::params_to_query_str(params);
32781 return Post(path, headers, query, "application/x-www-form-urlencoded");
32782}
32783
32784inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
32785 const Params &params, Progress progress) {
32786 auto query = detail::params_to_query_str(params);
32787 return Post(path, headers, query, "application/x-www-form-urlencoded",
32788 progress);
32789}
32790
32791inline Result ClientImpl::Post(const std::string &path,
32792 const MultipartFormDataItems &items) {
32793 return Post(path, Headers(), items);
32794}
32795
32796inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
32797 const MultipartFormDataItems &items) {
32798 const auto &boundary = detail::make_multipart_data_boundary();
32799 const auto &content_type =
32800 detail::serialize_multipart_formdata_get_content_type(boundary);
32801 const auto &body = detail::serialize_multipart_formdata(items, boundary);
32802 return Post(path, headers, body, content_type);
32803}
32804
32805inline Result ClientImpl::Post(const std::string &path, const Headers &headers,
32806 const MultipartFormDataItems &items,
32807 const std::string &boundary) {
32808 if (!detail::is_multipart_boundary_chars_valid(boundary)) {
32809 return Result{nullptr, Error::UnsupportedMultipartBoundaryChars};
32810 }
32811
32812 const auto &content_type =
32813 detail::serialize_multipart_formdata_get_content_type(boundary);
32814 const auto &body = detail::serialize_multipart_formdata(items, boundary);
32815 return Post(path, headers, body, content_type);
32816}
32817
32818inline Result
32819ClientImpl::Post(const std::string &path, const Headers &headers,
32820 const MultipartFormDataItems &items,
32821 const MultipartFormDataProviderItems &provider_items) {
32822 const auto &boundary = detail::make_multipart_data_boundary();
32823 const auto &content_type =
32824 detail::serialize_multipart_formdata_get_content_type(boundary);
32825 return send_with_content_provider(
32826 "POST", path, headers, nullptr, 0, nullptr,
32827 get_multipart_content_provider(boundary, items, provider_items),
32828 content_type, nullptr);
32829}
32830
32831inline Result ClientImpl::Put(const std::string &path) {
32832 return Put(path, std::string(), std::string());
32833}
32834
32835inline Result ClientImpl::Put(const std::string &path, const char *body,
32836 size_t content_length,
32837 const std::string &content_type) {
32838 return Put(path, Headers(), body, content_length, content_type);
32839}
32840
32841inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
32842 const char *body, size_t content_length,
32843 const std::string &content_type) {
32844 return send_with_content_provider("PUT", path, headers, body, content_length,
32845 nullptr, nullptr, content_type, nullptr);
32846}
32847
32848inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
32849 const char *body, size_t content_length,
32850 const std::string &content_type,
32851 Progress progress) {
32852 return send_with_content_provider("PUT", path, headers, body, content_length,
32853 nullptr, nullptr, content_type, progress);
32854}
32855
32856inline Result ClientImpl::Put(const std::string &path, const std::string &body,
32857 const std::string &content_type) {
32858 return Put(path, Headers(), body, content_type);
32859}
32860
32861inline Result ClientImpl::Put(const std::string &path, const std::string &body,
32862 const std::string &content_type,
32863 Progress progress) {
32864 return Put(path, Headers(), body, content_type, progress);
32865}
32866
32867inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
32868 const std::string &body,
32869 const std::string &content_type) {
32870 return send_with_content_provider("PUT", path, headers, body.data(),
32871 body.size(), nullptr, nullptr, content_type,
32872 nullptr);
32873}
32874
32875inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
32876 const std::string &body,
32877 const std::string &content_type,
32878 Progress progress) {
32879 return send_with_content_provider("PUT", path, headers, body.data(),
32880 body.size(), nullptr, nullptr, content_type,
32881 progress);
32882}
32883
32884inline Result ClientImpl::Put(const std::string &path, size_t content_length,
32885 ContentProvider content_provider,
32886 const std::string &content_type) {
32887 return Put(path, Headers(), content_length, std::move(content_provider),
32888 content_type);
32889}
32890
32891inline Result ClientImpl::Put(const std::string &path,
32892 ContentProviderWithoutLength content_provider,
32893 const std::string &content_type) {
32894 return Put(path, Headers(), std::move(content_provider), content_type);
32895}
32896
32897inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
32898 size_t content_length,
32899 ContentProvider content_provider,
32900 const std::string &content_type) {
32901 return send_with_content_provider("PUT", path, headers, nullptr,
32902 content_length, std::move(content_provider),
32903 nullptr, content_type, nullptr);
32904}
32905
32906inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
32907 ContentProviderWithoutLength content_provider,
32908 const std::string &content_type) {
32909 return send_with_content_provider("PUT", path, headers, nullptr, 0, nullptr,
32910 std::move(content_provider), content_type,
32911 nullptr);
32912}
32913
32914inline Result ClientImpl::Put(const std::string &path, const Params &params) {
32915 return Put(path, Headers(), params);
32916}
32917
32918inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
32919 const Params &params) {
32920 auto query = detail::params_to_query_str(params);
32921 return Put(path, headers, query, "application/x-www-form-urlencoded");
32922}
32923
32924inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
32925 const Params &params, Progress progress) {
32926 auto query = detail::params_to_query_str(params);
32927 return Put(path, headers, query, "application/x-www-form-urlencoded",
32928 progress);
32929}
32930
32931inline Result ClientImpl::Put(const std::string &path,
32932 const MultipartFormDataItems &items) {
32933 return Put(path, Headers(), items);
32934}
32935
32936inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
32937 const MultipartFormDataItems &items) {
32938 const auto &boundary = detail::make_multipart_data_boundary();
32939 const auto &content_type =
32940 detail::serialize_multipart_formdata_get_content_type(boundary);
32941 const auto &body = detail::serialize_multipart_formdata(items, boundary);
32942 return Put(path, headers, body, content_type);
32943}
32944
32945inline Result ClientImpl::Put(const std::string &path, const Headers &headers,
32946 const MultipartFormDataItems &items,
32947 const std::string &boundary) {
32948 if (!detail::is_multipart_boundary_chars_valid(boundary)) {
32949 return Result{nullptr, Error::UnsupportedMultipartBoundaryChars};
32950 }
32951
32952 const auto &content_type =
32953 detail::serialize_multipart_formdata_get_content_type(boundary);
32954 const auto &body = detail::serialize_multipart_formdata(items, boundary);
32955 return Put(path, headers, body, content_type);
32956}
32957
32958inline Result
32959ClientImpl::Put(const std::string &path, const Headers &headers,
32960 const MultipartFormDataItems &items,
32961 const MultipartFormDataProviderItems &provider_items) {
32962 const auto &boundary = detail::make_multipart_data_boundary();
32963 const auto &content_type =
32964 detail::serialize_multipart_formdata_get_content_type(boundary);
32965 return send_with_content_provider(
32966 "PUT", path, headers, nullptr, 0, nullptr,
32967 get_multipart_content_provider(boundary, items, provider_items),
32968 content_type, nullptr);
32969}
32970inline Result ClientImpl::Patch(const std::string &path) {
32971 return Patch(path, std::string(), std::string());
32972}
32973
32974inline Result ClientImpl::Patch(const std::string &path, const char *body,
32975 size_t content_length,
32976 const std::string &content_type) {
32977 return Patch(path, Headers(), body, content_length, content_type);
32978}
32979
32980inline Result ClientImpl::Patch(const std::string &path, const char *body,
32981 size_t content_length,
32982 const std::string &content_type,
32983 Progress progress) {
32984 return Patch(path, Headers(), body, content_length, content_type, progress);
32985}
32986
32987inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
32988 const char *body, size_t content_length,
32989 const std::string &content_type) {
32990 return Patch(path, headers, body, content_length, content_type, nullptr);
32991}
32992
32993inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
32994 const char *body, size_t content_length,
32995 const std::string &content_type,
32996 Progress progress) {
32997 return send_with_content_provider("PATCH", path, headers, body,
32998 content_length, nullptr, nullptr,
32999 content_type, progress);
33000}
33001
33002inline Result ClientImpl::Patch(const std::string &path,
33003 const std::string &body,
33004 const std::string &content_type) {
33005 return Patch(path, Headers(), body, content_type);
33006}
33007
33008inline Result ClientImpl::Patch(const std::string &path,
33009 const std::string &body,
33010 const std::string &content_type, Progress progress) {
33011 return Patch(path, Headers(), body, content_type, progress);
33012}
33013
33014inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
33015 const std::string &body,
33016 const std::string &content_type) {
33017 return Patch(path, headers, body, content_type, nullptr);
33018}
33019
33020inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
33021 const std::string &body,
33022 const std::string &content_type,
33023 Progress progress) {
33024 return send_with_content_provider("PATCH", path, headers, body.data(),
33025 body.size(), nullptr, nullptr, content_type,
33026 progress);
33027}
33028
33029inline Result ClientImpl::Patch(const std::string &path, size_t content_length,
33030 ContentProvider content_provider,
33031 const std::string &content_type) {
33032 return Patch(path, Headers(), content_length, std::move(content_provider),
33033 content_type);
33034}
33035
33036inline Result ClientImpl::Patch(const std::string &path,
33037 ContentProviderWithoutLength content_provider,
33038 const std::string &content_type) {
33039 return Patch(path, Headers(), std::move(content_provider), content_type);
33040}
33041
33042inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
33043 size_t content_length,
33044 ContentProvider content_provider,
33045 const std::string &content_type) {
33046 return send_with_content_provider("PATCH", path, headers, nullptr,
33047 content_length, std::move(content_provider),
33048 nullptr, content_type, nullptr);
33049}
33050
33051inline Result ClientImpl::Patch(const std::string &path, const Headers &headers,
33052 ContentProviderWithoutLength content_provider,
33053 const std::string &content_type) {
33054 return send_with_content_provider("PATCH", path, headers, nullptr, 0, nullptr,
33055 std::move(content_provider), content_type,
33056 nullptr);
33057}
33058
33059inline Result ClientImpl::Delete(const std::string &path) {
33060 return Delete(path, Headers(), std::string(), std::string());
33061}
33062
33063inline Result ClientImpl::Delete(const std::string &path,
33064 const Headers &headers) {
33065 return Delete(path, headers, std::string(), std::string());
33066}
33067
33068inline Result ClientImpl::Delete(const std::string &path, const char *body,
33069 size_t content_length,
33070 const std::string &content_type) {
33071 return Delete(path, Headers(), body, content_length, content_type);
33072}
33073
33074inline Result ClientImpl::Delete(const std::string &path, const char *body,
33075 size_t content_length,
33076 const std::string &content_type,
33077 Progress progress) {
33078 return Delete(path, Headers(), body, content_length, content_type, progress);
33079}
33080
33081inline Result ClientImpl::Delete(const std::string &path,
33082 const Headers &headers, const char *body,
33083 size_t content_length,
33084 const std::string &content_type) {
33085 return Delete(path, headers, body, content_length, content_type, nullptr);
33086}
33087
33088inline Result ClientImpl::Delete(const std::string &path,
33089 const Headers &headers, const char *body,
33090 size_t content_length,
33091 const std::string &content_type,
33092 Progress progress) {
33093 Request req;
33094 req.method = "DELETE";
33095 req.headers = headers;
33096 req.path = path;
33097 req.progress = progress;
33098
33099 if (!content_type.empty()) { req.set_header("Content-Type", content_type); }
33100 req.body.assign(body, content_length);
33101
33102 return send_(std::move(req));
33103}
33104
33105inline Result ClientImpl::Delete(const std::string &path,
33106 const std::string &body,
33107 const std::string &content_type) {
33108 return Delete(path, Headers(), body.data(), body.size(), content_type);
33109}
33110
33111inline Result ClientImpl::Delete(const std::string &path,
33112 const std::string &body,
33113 const std::string &content_type,
33114 Progress progress) {
33115 return Delete(path, Headers(), body.data(), body.size(), content_type,
33116 progress);
33117}
33118
33119inline Result ClientImpl::Delete(const std::string &path,
33120 const Headers &headers,
33121 const std::string &body,
33122 const std::string &content_type) {
33123 return Delete(path, headers, body.data(), body.size(), content_type);
33124}
33125
33126inline Result ClientImpl::Delete(const std::string &path,
33127 const Headers &headers,
33128 const std::string &body,
33129 const std::string &content_type,
33130 Progress progress) {
33131 return Delete(path, headers, body.data(), body.size(), content_type,
33132 progress);
33133}
33134
33135inline Result ClientImpl::Options(const std::string &path) {
33136 return Options(path, Headers());
33137}
33138
33139inline Result ClientImpl::Options(const std::string &path,
33140 const Headers &headers) {
33141 Request req;
33142 req.method = "OPTIONS";
33143 req.headers = headers;
33144 req.path = path;
33145
33146 return send_(std::move(req));
33147}
33148
33149inline void ClientImpl::stop() {
33150 std::lock_guard<std::mutex> guard(socket_mutex_);
33151
33152 // If there is anything ongoing right now, the ONLY thread-safe thing we can
33153 // do is to shutdown_socket, so that threads using this socket suddenly
33154 // discover they can't read/write any more and error out. Everything else
33155 // (closing the socket, shutting ssl down) is unsafe because these actions are
33156 // not thread-safe.
33157 if (socket_requests_in_flight_ > 0) {
33158 shutdown_socket(socket_);
33159
33160 // Aside from that, we set a flag for the socket to be closed when we're
33161 // done.
33162 socket_should_be_closed_when_request_is_done_ = true;
33163 return;
33164 }
33165
33166 // Otherwise, still holding the mutex, we can shut everything down ourselves
33167 shutdown_ssl(socket_, true);
33168 shutdown_socket(socket_);
33169 close_socket(socket_);
33170}
33171
33172inline std::string ClientImpl::host() const { return host_; }
33173
33174inline int ClientImpl::port() const { return port_; }
33175
33176inline size_t ClientImpl::is_socket_open() const {
33177 std::lock_guard<std::mutex> guard(socket_mutex_);
33178 return socket_.is_open();
33179}
33180
33181inline socket_t ClientImpl::socket() const { return socket_.sock; }
33182
33183inline void ClientImpl::set_connection_timeout(time_t sec, time_t usec) {
33184 connection_timeout_sec_ = sec;
33185 connection_timeout_usec_ = usec;
33186}
33187
33188inline void ClientImpl::set_read_timeout(time_t sec, time_t usec) {
33189 read_timeout_sec_ = sec;
33190 read_timeout_usec_ = usec;
33191}
33192
33193inline void ClientImpl::set_write_timeout(time_t sec, time_t usec) {
33194 write_timeout_sec_ = sec;
33195 write_timeout_usec_ = usec;
33196}
33197
33198inline void ClientImpl::set_basic_auth(const std::string &username,
33199 const std::string &password) {
33200 basic_auth_username_ = username;
33201 basic_auth_password_ = password;
33202}
33203
33204inline void ClientImpl::set_bearer_token_auth(const std::string &token) {
33205 bearer_token_auth_token_ = token;
33206}
33207
33208#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
33209inline void ClientImpl::set_digest_auth(const std::string &username,
33210 const std::string &password) {
33211 digest_auth_username_ = username;
33212 digest_auth_password_ = password;
33213}
33214#endif
33215
33216inline void ClientImpl::set_keep_alive(bool on) { keep_alive_ = on; }
33217
33218inline void ClientImpl::set_follow_location(bool on) { follow_location_ = on; }
33219
33220inline void ClientImpl::set_url_encode(bool on) { url_encode_ = on; }
33221
33222inline void
33223ClientImpl::set_hostname_addr_map(std::map<std::string, std::string> addr_map) {
33224 addr_map_ = std::move(addr_map);
33225}
33226
33227inline void ClientImpl::set_default_headers(Headers headers) {
33228 default_headers_ = std::move(headers);
33229}
33230
33231inline void ClientImpl::set_header_writer(
33232 std::function<ssize_t(Stream &, Headers &)> const &writer) {
33233 header_writer_ = writer;
33234}
33235
33236inline void ClientImpl::set_address_family(int family) {
33237 address_family_ = family;
33238}
33239
33240inline void ClientImpl::set_tcp_nodelay(bool on) { tcp_nodelay_ = on; }
33241
33242inline void ClientImpl::set_socket_options(SocketOptions socket_options) {
33243 socket_options_ = std::move(socket_options);
33244}
33245
33246inline void ClientImpl::set_compress(bool on) { compress_ = on; }
33247
33248inline void ClientImpl::set_decompress(bool on) { decompress_ = on; }
33249
33250inline void ClientImpl::set_interface(const std::string &intf) {
33251 interface_ = intf;
33252}
33253
33254inline void ClientImpl::set_proxy(const std::string &host, int port) {
33255 proxy_host_ = host;
33256 proxy_port_ = port;
33257}
33258
33259inline void ClientImpl::set_proxy_basic_auth(const std::string &username,
33260 const std::string &password) {
33261 proxy_basic_auth_username_ = username;
33262 proxy_basic_auth_password_ = password;
33263}
33264
33265inline void ClientImpl::set_proxy_bearer_token_auth(const std::string &token) {
33266 proxy_bearer_token_auth_token_ = token;
33267}
33268
33269#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
33270inline void ClientImpl::set_proxy_digest_auth(const std::string &username,
33271 const std::string &password) {
33272 proxy_digest_auth_username_ = username;
33273 proxy_digest_auth_password_ = password;
33274}
33275
33276inline void ClientImpl::set_ca_cert_path(const std::string &ca_cert_file_path,
33277 const std::string &ca_cert_dir_path) {
33278 ca_cert_file_path_ = ca_cert_file_path;
33279 ca_cert_dir_path_ = ca_cert_dir_path;
33280}
33281
33282inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) {
33283 if (ca_cert_store && ca_cert_store != ca_cert_store_) {
33284 ca_cert_store_ = ca_cert_store;
33285 }
33286}
33287
33288inline X509_STORE *ClientImpl::create_ca_cert_store(const char *ca_cert,
33289 std::size_t size) const {
33290 auto mem = BIO_new_mem_buf(ca_cert, static_cast<int>(size));
33291 if (!mem) { return nullptr; }
33292
33293 auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr);
33294 if (!inf) {
33295 BIO_free_all(mem);
33296 return nullptr;
33297 }
33298
33299 auto cts = X509_STORE_new();
33300 if (cts) {
33301 for (auto i = 0; i < static_cast<int>(sk_X509_INFO_num(inf)); i++) {
33302 auto itmp = sk_X509_INFO_value(inf, i);
33303 if (!itmp) { continue; }
33304
33305 if (itmp->x509) { X509_STORE_add_cert(cts, itmp->x509); }
33306 if (itmp->crl) { X509_STORE_add_crl(cts, itmp->crl); }
33307 }
33308 }
33309
33310 sk_X509_INFO_pop_free(inf, X509_INFO_free);
33311 BIO_free_all(mem);
33312 return cts;
33313}
33314
33315inline void ClientImpl::enable_server_certificate_verification(bool enabled) {
33316 server_certificate_verification_ = enabled;
33317}
33318#endif
33319
33320inline void ClientImpl::set_logger(Logger logger) {
33321 logger_ = std::move(logger);
33322}
33323
33324/*
33325 * SSL Implementation
33326 */
33327#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
33328namespace detail {
33329
33330template <typename U, typename V>
33331inline SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex,
33332 U SSL_connect_or_accept, V setup) {
33333 SSL *ssl = nullptr;
33334 {
33335 std::lock_guard<std::mutex> guard(ctx_mutex);
33336 ssl = SSL_new(ctx);
33337 }
33338
33339 if (ssl) {
33340 set_nonblocking(sock, true);
33341 auto bio = BIO_new_socket(static_cast<int>(sock), BIO_NOCLOSE);
33342 BIO_set_nbio(bio, 1);
33343 SSL_set_bio(ssl, bio, bio);
33344
33345 if (!setup(ssl) || SSL_connect_or_accept(ssl) != 1) {
33346 SSL_shutdown(ssl);
33347 {
33348 std::lock_guard<std::mutex> guard(ctx_mutex);
33349 SSL_free(ssl);
33350 }
33351 set_nonblocking(sock, false);
33352 return nullptr;
33353 }
33354 BIO_set_nbio(bio, 0);
33355 set_nonblocking(sock, false);
33356 }
33357
33358 return ssl;
33359}
33360
33361inline void ssl_delete(std::mutex &ctx_mutex, SSL *ssl,
33362 bool shutdown_gracefully) {
33363 // sometimes we may want to skip this to try to avoid SIGPIPE if we know
33364 // the remote has closed the network connection
33365 // Note that it is not always possible to avoid SIGPIPE, this is merely a
33366 // best-efforts.
33367 if (shutdown_gracefully) { SSL_shutdown(ssl); }
33368
33369 std::lock_guard<std::mutex> guard(ctx_mutex);
33370 SSL_free(ssl);
33371}
33372
33373template <typename U>
33374bool ssl_connect_or_accept_nonblocking(socket_t sock, SSL *ssl,
33375 U ssl_connect_or_accept,
33376 time_t timeout_sec,
33377 time_t timeout_usec) {
33378 auto res = 0;
33379 while ((res = ssl_connect_or_accept(ssl)) != 1) {
33380 auto err = SSL_get_error(ssl, res);
33381 switch (err) {
33382 case SSL_ERROR_WANT_READ:
33383 if (select_read(sock, timeout_sec, timeout_usec) > 0) { continue; }
33384 break;
33385 case SSL_ERROR_WANT_WRITE:
33386 if (select_write(sock, timeout_sec, timeout_usec) > 0) { continue; }
33387 break;
33388 default: break;
33389 }
33390 return false;
33391 }
33392 return true;
33393}
33394
33395template <typename T>
33396inline bool process_server_socket_ssl(
33397 const std::atomic<socket_t> &svr_sock, SSL *ssl, socket_t sock,
33398 size_t keep_alive_max_count, time_t keep_alive_timeout_sec,
33399 time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
33400 time_t write_timeout_usec, T callback) {
33401 return process_server_socket_core(
33402 svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec,
33403 [&](bool close_connection, bool &connection_closed) {
33404 SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec,
33405 write_timeout_sec, write_timeout_usec);
33406 return callback(strm, close_connection, connection_closed);
33407 });
33408}
33409
33410template <typename T>
33411inline bool
33412process_client_socket_ssl(SSL *ssl, socket_t sock, time_t read_timeout_sec,
33413 time_t read_timeout_usec, time_t write_timeout_sec,
33414 time_t write_timeout_usec, T callback) {
33415 SSLSocketStream strm(sock, ssl, read_timeout_sec, read_timeout_usec,
33416 write_timeout_sec, write_timeout_usec);
33417 return callback(strm);
33418}
33419
33420class SSLInit {
33421public:
33422 SSLInit() {
33423 OPENSSL_init_ssl(
33424 OPENSSL_INIT_LOAD_SSL_STRINGS | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
33425 }
33426};
33427
33428// SSL socket stream implementation
33429inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl,
33430 time_t read_timeout_sec,
33431 time_t read_timeout_usec,
33432 time_t write_timeout_sec,
33433 time_t write_timeout_usec)
33434 : sock_(sock), ssl_(ssl), read_timeout_sec_(read_timeout_sec),
33435 read_timeout_usec_(read_timeout_usec),
33436 write_timeout_sec_(write_timeout_sec),
33437 write_timeout_usec_(write_timeout_usec) {
33438 SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
33439}
33440
33441inline SSLSocketStream::~SSLSocketStream() = default;
33442
33443inline bool SSLSocketStream::is_readable() const {
33444 return detail::select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
33445}
33446
33447inline bool SSLSocketStream::is_writable() const {
33448 return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 &&
33449 is_socket_alive(sock_);
33450}
33451
33452inline ssize_t SSLSocketStream::read(char *ptr, size_t size) {
33453 if (SSL_pending(ssl_) > 0) {
33454 return SSL_read(ssl_, ptr, static_cast<int>(size));
33455 } else if (is_readable()) {
33456 auto ret = SSL_read(ssl_, ptr, static_cast<int>(size));
33457 if (ret < 0) {
33458 auto err = SSL_get_error(ssl_, ret);
33459 auto n = 1000;
33460#ifdef _WIN32
33461 while (--n >= 0 && (err == SSL_ERROR_WANT_READ ||
33462 (err == SSL_ERROR_SYSCALL &&
33463 WSAGetLastError() == WSAETIMEDOUT))) {
33464#else
33465 while (--n >= 0 && err == SSL_ERROR_WANT_READ) {
33466#endif
33467 if (SSL_pending(ssl_) > 0) {
33468 return SSL_read(ssl_, ptr, static_cast<int>(size));
33469 } else if (is_readable()) {
33470 std::this_thread::sleep_for(std::chrono::milliseconds(1));
33471 ret = SSL_read(ssl_, ptr, static_cast<int>(size));
33472 if (ret >= 0) { return ret; }
33473 err = SSL_get_error(ssl_, ret);
33474 } else {
33475 return -1;
33476 }
33477 }
33478 }
33479 return ret;
33480 }
33481 return -1;
33482}
33483
33484inline ssize_t SSLSocketStream::write(const char *ptr, size_t size) {
33485 if (is_writable()) {
33486 auto handle_size = static_cast<int>(
33487 std::min<size_t>(size, (std::numeric_limits<int>::max)()));
33488
33489 auto ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
33490 if (ret < 0) {
33491 auto err = SSL_get_error(ssl_, ret);
33492 auto n = 1000;
33493#ifdef _WIN32
33494 while (--n >= 0 && (err == SSL_ERROR_WANT_WRITE ||
33495 (err == SSL_ERROR_SYSCALL &&
33496 WSAGetLastError() == WSAETIMEDOUT))) {
33497#else
33498 while (--n >= 0 && err == SSL_ERROR_WANT_WRITE) {
33499#endif
33500 if (is_writable()) {
33501 std::this_thread::sleep_for(std::chrono::milliseconds(1));
33502 ret = SSL_write(ssl_, ptr, static_cast<int>(handle_size));
33503 if (ret >= 0) { return ret; }
33504 err = SSL_get_error(ssl_, ret);
33505 } else {
33506 return -1;
33507 }
33508 }
33509 }
33510 return ret;
33511 }
33512 return -1;
33513}
33514
33515inline void SSLSocketStream::get_remote_ip_and_port(std::string &ip,
33516 int &port) const {
33517 detail::get_remote_ip_and_port(sock_, ip, port);
33518}
33519
33520inline void SSLSocketStream::get_local_ip_and_port(std::string &ip,
33521 int &port) const {
33522 detail::get_local_ip_and_port(sock_, ip, port);
33523}
33524
33525inline socket_t SSLSocketStream::socket() const { return sock_; }
33526
33527static SSLInit sslinit_;
33528
33529} // namespace detail
33530
33531// SSL HTTP server implementation
33532inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path,
33533 const char *client_ca_cert_file_path,
33534 const char *client_ca_cert_dir_path,
33535 const char *private_key_password) {
33536 ctx_ = SSL_CTX_new(TLS_server_method());
33537
33538 if (ctx_) {
33539 SSL_CTX_set_options(ctx_,
33540 SSL_OP_NO_COMPRESSION |
33541 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
33542
33543 SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION);
33544
33545 if (private_key_password != nullptr && (private_key_password[0] != '\0')) {
33546 SSL_CTX_set_default_passwd_cb_userdata(
33547 ctx_,
33548 reinterpret_cast<void *>(const_cast<char *>(private_key_password)));
33549 }
33550
33551 if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 ||
33552 SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) !=
33553 1) {
33554 SSL_CTX_free(ctx_);
33555 ctx_ = nullptr;
33556 } else if (client_ca_cert_file_path || client_ca_cert_dir_path) {
33557 SSL_CTX_load_verify_locations(ctx_, client_ca_cert_file_path,
33558 client_ca_cert_dir_path);
33559
33560 SSL_CTX_set_verify(
33561 ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
33562 }
33563 }
33564}
33565
33566inline SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key,
33567 X509_STORE *client_ca_cert_store) {
33568 ctx_ = SSL_CTX_new(TLS_server_method());
33569
33570 if (ctx_) {
33571 SSL_CTX_set_options(ctx_,
33572 SSL_OP_NO_COMPRESSION |
33573 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
33574
33575 SSL_CTX_set_min_proto_version(ctx_, TLS1_1_VERSION);
33576
33577 if (SSL_CTX_use_certificate(ctx_, cert) != 1 ||
33578 SSL_CTX_use_PrivateKey(ctx_, private_key) != 1) {
33579 SSL_CTX_free(ctx_);
33580 ctx_ = nullptr;
33581 } else if (client_ca_cert_store) {
33582 SSL_CTX_set_cert_store(ctx_, client_ca_cert_store);
33583
33584 SSL_CTX_set_verify(
33585 ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
33586 }
33587 }
33588}
33589
33590inline SSLServer::SSLServer(
33591 const std::function<bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback) {
33592 ctx_ = SSL_CTX_new(TLS_method());
33593 if (ctx_) {
33594 if (!setup_ssl_ctx_callback(*ctx_)) {
33595 SSL_CTX_free(ctx_);
33596 ctx_ = nullptr;
33597 }
33598 }
33599}
33600
33601inline SSLServer::~SSLServer() {
33602 if (ctx_) { SSL_CTX_free(ctx_); }
33603}
33604
33605inline bool SSLServer::is_valid() const { return ctx_; }
33606
33607inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; }
33608
33609inline bool SSLServer::process_and_close_socket(socket_t sock) {
33610 auto ssl = detail::ssl_new(
33611 sock, ctx_, ctx_mutex_,
33612 [&](SSL *ssl2) {
33613 return detail::ssl_connect_or_accept_nonblocking(
33614 sock, ssl2, SSL_accept, read_timeout_sec_, read_timeout_usec_);
33615 },
33616 [](SSL * /*ssl2*/) { return true; });
33617
33618 auto ret = false;
33619 if (ssl) {
33620 ret = detail::process_server_socket_ssl(
33621 svr_sock_, ssl, sock, keep_alive_max_count_, keep_alive_timeout_sec_,
33622 read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
33623 write_timeout_usec_,
33624 [this, ssl](Stream &strm, bool close_connection,
33625 bool &connection_closed) {
33626 return process_request(strm, close_connection, connection_closed,
33627 [&](Request &req) { req.ssl = ssl; });
33628 });
33629
33630 // Shutdown gracefully if the result seemed successful, non-gracefully if
33631 // the connection appeared to be closed.
33632 const bool shutdown_gracefully = ret;
33633 detail::ssl_delete(ctx_mutex_, ssl, shutdown_gracefully);
33634 }
33635
33636 detail::shutdown_socket(sock);
33637 detail::close_socket(sock);
33638 return ret;
33639}
33640
33641// SSL HTTP client implementation
33642inline SSLClient::SSLClient(const std::string &host)
33643 : SSLClient(host, 443, std::string(), std::string()) {}
33644
33645inline SSLClient::SSLClient(const std::string &host, int port)
33646 : SSLClient(host, port, std::string(), std::string()) {}
33647
33648inline SSLClient::SSLClient(const std::string &host, int port,
33649 const std::string &client_cert_path,
33650 const std::string &client_key_path,
33651 const std::string &private_key_password)
33652 : ClientImpl(host, port, client_cert_path, client_key_path) {
33653 ctx_ = SSL_CTX_new(TLS_client_method());
33654
33655 detail::split(&host_[0], &host_[host_.size()], '.',
33656 [&](const char *b, const char *e) {
33657 host_components_.emplace_back(b, e);
33658 });
33659
33660 if (!client_cert_path.empty() && !client_key_path.empty()) {
33661 if (!private_key_password.empty()) {
33662 SSL_CTX_set_default_passwd_cb_userdata(
33663 ctx_, reinterpret_cast<void *>(
33664 const_cast<char *>(private_key_password.c_str())));
33665 }
33666
33667 if (SSL_CTX_use_certificate_file(ctx_, client_cert_path.c_str(),
33668 SSL_FILETYPE_PEM) != 1 ||
33669 SSL_CTX_use_PrivateKey_file(ctx_, client_key_path.c_str(),
33670 SSL_FILETYPE_PEM) != 1) {
33671 SSL_CTX_free(ctx_);
33672 ctx_ = nullptr;
33673 }
33674 }
33675}
33676
33677inline SSLClient::SSLClient(const std::string &host, int port,
33678 X509 *client_cert, EVP_PKEY *client_key,
33679 const std::string &private_key_password)
33680 : ClientImpl(host, port) {
33681 ctx_ = SSL_CTX_new(TLS_client_method());
33682
33683 detail::split(&host_[0], &host_[host_.size()], '.',
33684 [&](const char *b, const char *e) {
33685 host_components_.emplace_back(b, e);
33686 });
33687
33688 if (client_cert != nullptr && client_key != nullptr) {
33689 if (!private_key_password.empty()) {
33690 SSL_CTX_set_default_passwd_cb_userdata(
33691 ctx_, reinterpret_cast<void *>(
33692 const_cast<char *>(private_key_password.c_str())));
33693 }
33694
33695 if (SSL_CTX_use_certificate(ctx_, client_cert) != 1 ||
33696 SSL_CTX_use_PrivateKey(ctx_, client_key) != 1) {
33697 SSL_CTX_free(ctx_);
33698 ctx_ = nullptr;
33699 }
33700 }
33701}
33702
33703inline SSLClient::~SSLClient() {
33704 if (ctx_) { SSL_CTX_free(ctx_); }
33705 // Make sure to shut down SSL since shutdown_ssl will resolve to the
33706 // base function rather than the derived function once we get to the
33707 // base class destructor, and won't free the SSL (causing a leak).
33708 shutdown_ssl_impl(socket_, true);
33709}
33710
33711inline bool SSLClient::is_valid() const { return ctx_; }
33712
33713inline void SSLClient::set_ca_cert_store(X509_STORE *ca_cert_store) {
33714 if (ca_cert_store) {
33715 if (ctx_) {
33716 if (SSL_CTX_get_cert_store(ctx_) != ca_cert_store) {
33717 // Free memory allocated for old cert and use new store `ca_cert_store`
33718 SSL_CTX_set_cert_store(ctx_, ca_cert_store);
33719 }
33720 } else {
33721 X509_STORE_free(ca_cert_store);
33722 }
33723 }
33724}
33725
33726inline void SSLClient::load_ca_cert_store(const char *ca_cert,
33727 std::size_t size) {
33728 set_ca_cert_store(ClientImpl::create_ca_cert_store(ca_cert, size));
33729}
33730
33731inline long SSLClient::get_openssl_verify_result() const {
33732 return verify_result_;
33733}
33734
33735inline SSL_CTX *SSLClient::ssl_context() const { return ctx_; }
33736
33737inline bool SSLClient::create_and_connect_socket(Socket &socket, Error &error) {
33738 return is_valid() && ClientImpl::create_and_connect_socket(socket, error);
33739}
33740
33741// Assumes that socket_mutex_ is locked and that there are no requests in flight
33742inline bool SSLClient::connect_with_proxy(Socket &socket, Response &res,
33743 bool &success, Error &error) {
33744 success = true;
33745 Response proxy_res;
33746 if (!detail::process_client_socket(
33747 socket.sock, read_timeout_sec_, read_timeout_usec_,
33748 write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
33749 Request req2;
33750 req2.method = "CONNECT";
33751 req2.path = host_and_port_;
33752 return process_request(strm, req2, proxy_res, false, error);
33753 })) {
33754 // Thread-safe to close everything because we are assuming there are no
33755 // requests in flight
33756 shutdown_ssl(socket, true);
33757 shutdown_socket(socket);
33758 close_socket(socket);
33759 success = false;
33760 return false;
33761 }
33762
33763 if (proxy_res.status == StatusCode::ProxyAuthenticationRequired_407) {
33764 if (!proxy_digest_auth_username_.empty() &&
33765 !proxy_digest_auth_password_.empty()) {
33766 std::map<std::string, std::string> auth;
33767 if (detail::parse_www_authenticate(proxy_res, auth, true)) {
33768 proxy_res = Response();
33769 if (!detail::process_client_socket(
33770 socket.sock, read_timeout_sec_, read_timeout_usec_,
33771 write_timeout_sec_, write_timeout_usec_, [&](Stream &strm) {
33772 Request req3;
33773 req3.method = "CONNECT";
33774 req3.path = host_and_port_;
33775 req3.headers.insert(detail::make_digest_authentication_header(
33776 req3, auth, 1, detail::random_string(10),
33777 proxy_digest_auth_username_, proxy_digest_auth_password_,
33778 true));
33779 return process_request(strm, req3, proxy_res, false, error);
33780 })) {
33781 // Thread-safe to close everything because we are assuming there are
33782 // no requests in flight
33783 shutdown_ssl(socket, true);
33784 shutdown_socket(socket);
33785 close_socket(socket);
33786 success = false;
33787 return false;
33788 }
33789 }
33790 }
33791 }
33792
33793 // If status code is not 200, proxy request is failed.
33794 // Set error to ProxyConnection and return proxy response
33795 // as the response of the request
33796 if (proxy_res.status != StatusCode::OK_200) {
33797 error = Error::ProxyConnection;
33798 res = std::move(proxy_res);
33799 // Thread-safe to close everything because we are assuming there are
33800 // no requests in flight
33801 shutdown_ssl(socket, true);
33802 shutdown_socket(socket);
33803 close_socket(socket);
33804 return false;
33805 }
33806
33807 return true;
33808}
33809
33810inline bool SSLClient::load_certs() {
33811 auto ret = true;
33812
33813 std::call_once(initialize_cert_, [&]() {
33814 std::lock_guard<std::mutex> guard(ctx_mutex_);
33815 if (!ca_cert_file_path_.empty()) {
33816 if (!SSL_CTX_load_verify_locations(ctx_, ca_cert_file_path_.c_str(),
33817 nullptr)) {
33818 ret = false;
33819 }
33820 } else if (!ca_cert_dir_path_.empty()) {
33821 if (!SSL_CTX_load_verify_locations(ctx_, nullptr,
33822 ca_cert_dir_path_.c_str())) {
33823 ret = false;
33824 }
33825 } else {
33826 auto loaded = false;
33827#ifdef _WIN32
33828 loaded =
33829 detail::load_system_certs_on_windows(SSL_CTX_get_cert_store(ctx_));
33830#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)
33831#if TARGET_OS_OSX
33832 loaded = detail::load_system_certs_on_macos(SSL_CTX_get_cert_store(ctx_));
33833#endif // TARGET_OS_OSX
33834#endif // _WIN32
33835 if (!loaded) { SSL_CTX_set_default_verify_paths(ctx_); }
33836 }
33837 });
33838
33839 return ret;
33840}
33841
33842inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) {
33843 auto ssl = detail::ssl_new(
33844 socket.sock, ctx_, ctx_mutex_,
33845 [&](SSL *ssl2) {
33846 if (server_certificate_verification_) {
33847 if (!load_certs()) {
33848 error = Error::SSLLoadingCerts;
33849 return false;
33850 }
33851 SSL_set_verify(ssl2, SSL_VERIFY_NONE, nullptr);
33852 }
33853
33854 if (!detail::ssl_connect_or_accept_nonblocking(
33855 socket.sock, ssl2, SSL_connect, connection_timeout_sec_,
33856 connection_timeout_usec_)) {
33857 error = Error::SSLConnection;
33858 return false;
33859 }
33860
33861 if (server_certificate_verification_) {
33862 verify_result_ = SSL_get_verify_result(ssl2);
33863
33864 if (verify_result_ != X509_V_OK) {
33865 error = Error::SSLServerVerification;
33866 return false;
33867 }
33868
33869 auto server_cert = SSL_get1_peer_certificate(ssl2);
33870
33871 if (server_cert == nullptr) {
33872 error = Error::SSLServerVerification;
33873 return false;
33874 }
33875
33876 if (!verify_host(server_cert)) {
33877 X509_free(server_cert);
33878 error = Error::SSLServerVerification;
33879 return false;
33880 }
33881 X509_free(server_cert);
33882 }
33883
33884 return true;
33885 },
33886 [&](SSL *ssl2) {
33887 // NOTE: Direct call instead of using the OpenSSL macro to suppress
33888 // -Wold-style-cast warning
33889 // SSL_set_tlsext_host_name(ssl2, host_.c_str());
33890 SSL_ctrl(ssl2, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name,
33891 static_cast<void *>(const_cast<char *>(host_.c_str())));
33892 return true;
33893 });
33894
33895 if (ssl) {
33896 socket.ssl = ssl;
33897 return true;
33898 }
33899
33900 shutdown_socket(socket);
33901 close_socket(socket);
33902 return false;
33903}
33904
33905inline void SSLClient::shutdown_ssl(Socket &socket, bool shutdown_gracefully) {
33906 shutdown_ssl_impl(socket, shutdown_gracefully);
33907}
33908
33909inline void SSLClient::shutdown_ssl_impl(Socket &socket,
33910 bool shutdown_gracefully) {
33911 if (socket.sock == INVALID_SOCKET) {
33912 assert(socket.ssl == nullptr);
33913 return;
33914 }
33915 if (socket.ssl) {
33916 detail::ssl_delete(ctx_mutex_, socket.ssl, shutdown_gracefully);
33917 socket.ssl = nullptr;
33918 }
33919 assert(socket.ssl == nullptr);
33920}
33921
33922inline bool
33923SSLClient::process_socket(const Socket &socket,
33924 std::function<bool(Stream &strm)> callback) {
33925 assert(socket.ssl);
33926 return detail::process_client_socket_ssl(
33927 socket.ssl, socket.sock, read_timeout_sec_, read_timeout_usec_,
33928 write_timeout_sec_, write_timeout_usec_, std::move(callback));
33929}
33930
33931inline bool SSLClient::is_ssl() const { return true; }
33932
33933inline bool SSLClient::verify_host(X509 *server_cert) const {
33934 /* Quote from RFC2818 section 3.1 "Server Identity"
33935
33936 If a subjectAltName extension of type dNSName is present, that MUST
33937 be used as the identity. Otherwise, the (most specific) Common Name
33938 field in the Subject field of the certificate MUST be used. Although
33939 the use of the Common Name is existing practice, it is deprecated and
33940 Certification Authorities are encouraged to use the dNSName instead.
33941
33942 Matching is performed using the matching rules specified by
33943 [RFC2459]. If more than one identity of a given type is present in
33944 the certificate (e.g., more than one dNSName name, a match in any one
33945 of the set is considered acceptable.) Names may contain the wildcard
33946 character * which is considered to match any single domain name
33947 component or component fragment. E.g., *.a.com matches foo.a.com but
33948 not bar.foo.a.com. f*.com matches foo.com but not bar.com.
33949
33950 In some cases, the URI is specified as an IP address rather than a
33951 hostname. In this case, the iPAddress subjectAltName must be present
33952 in the certificate and must exactly match the IP in the URI.
33953
33954 */
33955 return verify_host_with_subject_alt_name(server_cert) ||
33956 verify_host_with_common_name(server_cert);
33957}
33958
33959inline bool
33960SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const {
33961 auto ret = false;
33962
33963 auto type = GEN_DNS;
33964
33965 struct in6_addr addr6 {};
33966 struct in_addr addr {};
33967 size_t addr_len = 0;
33968
33969#ifndef __MINGW32__
33970 if (inet_pton(AF_INET6, host_.c_str(), &addr6)) {
33971 type = GEN_IPADD;
33972 addr_len = sizeof(struct in6_addr);
33973 } else if (inet_pton(AF_INET, host_.c_str(), &addr)) {
33974 type = GEN_IPADD;
33975 addr_len = sizeof(struct in_addr);
33976 }
33977#endif
33978
33979 auto alt_names = static_cast<const struct stack_st_GENERAL_NAME *>(
33980 X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr));
33981
33982 if (alt_names) {
33983 auto dsn_matched = false;
33984 auto ip_matched = false;
33985
33986 auto count = sk_GENERAL_NAME_num(alt_names);
33987
33988 for (decltype(count) i = 0; i < count && !dsn_matched; i++) {
33989 auto val = sk_GENERAL_NAME_value(alt_names, i);
33990 if (val->type == type) {
33991 auto name =
33992 reinterpret_cast<const char *>(ASN1_STRING_get0_data(val->d.ia5));
33993 auto name_len = static_cast<size_t>(ASN1_STRING_length(val->d.ia5));
33994
33995 switch (type) {
33996 case GEN_DNS: dsn_matched = check_host_name(name, name_len); break;
33997
33998 case GEN_IPADD:
33999 if (!memcmp(&addr6, name, addr_len) ||
34000 !memcmp(&addr, name, addr_len)) {
34001 ip_matched = true;
34002 }
34003 break;
34004 }
34005 }
34006 }
34007
34008 if (dsn_matched || ip_matched) { ret = true; }
34009 }
34010
34011 GENERAL_NAMES_free(const_cast<STACK_OF(GENERAL_NAME) *>(
34012 reinterpret_cast<const STACK_OF(GENERAL_NAME) *>(alt_names)));
34013 return ret;
34014}
34015
34016inline bool SSLClient::verify_host_with_common_name(X509 *server_cert) const {
34017 const auto subject_name = X509_get_subject_name(server_cert);
34018
34019 if (subject_name != nullptr) {
34020 char name[BUFSIZ];
34021 auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName,
34022 name, sizeof(name));
34023
34024 if (name_len != -1) {
34025 return check_host_name(name, static_cast<size_t>(name_len));
34026 }
34027 }
34028
34029 return false;
34030}
34031
34032inline bool SSLClient::check_host_name(const char *pattern,
34033 size_t pattern_len) const {
34034 if (host_.size() == pattern_len && host_ == pattern) { return true; }
34035
34036 // Wildcard match
34037 // https://bugs.launchpad.net/ubuntu/+source/firefox-3.0/+bug/376484
34038 std::vector<std::string> pattern_components;
34039 detail::split(&pattern[0], &pattern[pattern_len], '.',
34040 [&](const char *b, const char *e) {
34041 pattern_components.emplace_back(b, e);
34042 });
34043
34044 if (host_components_.size() != pattern_components.size()) { return false; }
34045
34046 auto itr = pattern_components.begin();
34047 for (const auto &h : host_components_) {
34048 auto &p = *itr;
34049 if (p != h && p != "*") {
34050 auto partial_match = (p.size() > 0 && p[p.size() - 1] == '*' &&
34051 !p.compare(0, p.size() - 1, h));
34052 if (!partial_match) { return false; }
34053 }
34054 ++itr;
34055 }
34056
34057 return true;
34058}
34059#endif
34060
34061// Universal client implementation
34062inline Client::Client(const std::string &scheme_host_port)
34063 : Client(scheme_host_port, std::string(), std::string()) {}
34064
34065inline Client::Client(const std::string &scheme_host_port,
34066 const std::string &client_cert_path,
34067 const std::string &client_key_path) {
34068 const static std::regex re(
34069 R"((?:([a-z]+):\/\/)?(?:\[([\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
34070
34071 std::smatch m;
34072 if (std::regex_match(scheme_host_port, m, re)) {
34073 auto scheme = m[1].str();
34074
34075#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
34076 if (!scheme.empty() && (scheme != "http" && scheme != "https")) {
34077#else
34078 if (!scheme.empty() && scheme != "http") {
34079#endif
34080#ifndef CPPHTTPLIB_NO_EXCEPTIONS
34081 std::string msg = "'" + scheme + "' scheme is not supported.";
34082 throw std::invalid_argument(msg);
34083#endif
34084 return;
34085 }
34086
34087 auto is_ssl = scheme == "https";
34088
34089 auto host = m[2].str();
34090 if (host.empty()) { host = m[3].str(); }
34091
34092 auto port_str = m[4].str();
34093 auto port = !port_str.empty() ? std::stoi(port_str) : (is_ssl ? 443 : 80);
34094
34095 if (is_ssl) {
34096#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
34097 cli_ = detail::make_unique<SSLClient>(host, port, client_cert_path,
34098 client_key_path);
34099 is_ssl_ = is_ssl;
34100#endif
34101 } else {
34102 cli_ = detail::make_unique<ClientImpl>(host, port, client_cert_path,
34103 client_key_path);
34104 }
34105 } else {
34106 cli_ = detail::make_unique<ClientImpl>(scheme_host_port, 80,
34107 client_cert_path, client_key_path);
34108 }
34109}
34110
34111inline Client::Client(const std::string &host, int port)
34112 : cli_(detail::make_unique<ClientImpl>(host, port)) {}
34113
34114inline Client::Client(const std::string &host, int port,
34115 const std::string &client_cert_path,
34116 const std::string &client_key_path)
34117 : cli_(detail::make_unique<ClientImpl>(host, port, client_cert_path,
34118 client_key_path)) {}
34119
34120inline Client::~Client() = default;
34121
34122inline bool Client::is_valid() const {
34123 return cli_ != nullptr && cli_->is_valid();
34124}
34125
34126inline Result Client::Get(const std::string &path) { return cli_->Get(path); }
34127inline Result Client::Get(const std::string &path, const Headers &headers) {
34128 return cli_->Get(path, headers);
34129}
34130inline Result Client::Get(const std::string &path, Progress progress) {
34131 return cli_->Get(path, std::move(progress));
34132}
34133inline Result Client::Get(const std::string &path, const Headers &headers,
34134 Progress progress) {
34135 return cli_->Get(path, headers, std::move(progress));
34136}
34137inline Result Client::Get(const std::string &path,
34138 ContentReceiver content_receiver) {
34139 return cli_->Get(path, std::move(content_receiver));
34140}
34141inline Result Client::Get(const std::string &path, const Headers &headers,
34142 ContentReceiver content_receiver) {
34143 return cli_->Get(path, headers, std::move(content_receiver));
34144}
34145inline Result Client::Get(const std::string &path,
34146 ContentReceiver content_receiver, Progress progress) {
34147 return cli_->Get(path, std::move(content_receiver), std::move(progress));
34148}
34149inline Result Client::Get(const std::string &path, const Headers &headers,
34150 ContentReceiver content_receiver, Progress progress) {
34151 return cli_->Get(path, headers, std::move(content_receiver),
34152 std::move(progress));
34153}
34154inline Result Client::Get(const std::string &path,
34155 ResponseHandler response_handler,
34156 ContentReceiver content_receiver) {
34157 return cli_->Get(path, std::move(response_handler),
34158 std::move(content_receiver));
34159}
34160inline Result Client::Get(const std::string &path, const Headers &headers,
34161 ResponseHandler response_handler,
34162 ContentReceiver content_receiver) {
34163 return cli_->Get(path, headers, std::move(response_handler),
34164 std::move(content_receiver));
34165}
34166inline Result Client::Get(const std::string &path,
34167 ResponseHandler response_handler,
34168 ContentReceiver content_receiver, Progress progress) {
34169 return cli_->Get(path, std::move(response_handler),
34170 std::move(content_receiver), std::move(progress));
34171}
34172inline Result Client::Get(const std::string &path, const Headers &headers,
34173 ResponseHandler response_handler,
34174 ContentReceiver content_receiver, Progress progress) {
34175 return cli_->Get(path, headers, std::move(response_handler),
34176 std::move(content_receiver), std::move(progress));
34177}
34178inline Result Client::Get(const std::string &path, const Params &params,
34179 const Headers &headers, Progress progress) {
34180 return cli_->Get(path, params, headers, std::move(progress));
34181}
34182inline Result Client::Get(const std::string &path, const Params &params,
34183 const Headers &headers,
34184 ContentReceiver content_receiver, Progress progress) {
34185 return cli_->Get(path, params, headers, std::move(content_receiver),
34186 std::move(progress));
34187}
34188inline Result Client::Get(const std::string &path, const Params &params,
34189 const Headers &headers,
34190 ResponseHandler response_handler,
34191 ContentReceiver content_receiver, Progress progress) {
34192 return cli_->Get(path, params, headers, std::move(response_handler),
34193 std::move(content_receiver), std::move(progress));
34194}
34195
34196inline Result Client::Head(const std::string &path) { return cli_->Head(path); }
34197inline Result Client::Head(const std::string &path, const Headers &headers) {
34198 return cli_->Head(path, headers);
34199}
34200
34201inline Result Client::Post(const std::string &path) { return cli_->Post(path); }
34202inline Result Client::Post(const std::string &path, const Headers &headers) {
34203 return cli_->Post(path, headers);
34204}
34205inline Result Client::Post(const std::string &path, const char *body,
34206 size_t content_length,
34207 const std::string &content_type) {
34208 return cli_->Post(path, body, content_length, content_type);
34209}
34210inline Result Client::Post(const std::string &path, const Headers &headers,
34211 const char *body, size_t content_length,
34212 const std::string &content_type) {
34213 return cli_->Post(path, headers, body, content_length, content_type);
34214}
34215inline Result Client::Post(const std::string &path, const Headers &headers,
34216 const char *body, size_t content_length,
34217 const std::string &content_type, Progress progress) {
34218 return cli_->Post(path, headers, body, content_length, content_type,
34219 progress);
34220}
34221inline Result Client::Post(const std::string &path, const std::string &body,
34222 const std::string &content_type) {
34223 return cli_->Post(path, body, content_type);
34224}
34225
34226inline Result Client::Post(const std::string &path, const std::string &body,
34227 const std::string &content_type, ContentReceiver content_receiver) {
34228 return cli_->Post(path, body, content_type, std::move(content_receiver));
34229}
34230
34231inline Result Client::Post(const std::string &path, const std::string &body,
34232 const std::string &content_type, Progress progress) {
34233 return cli_->Post(path, body, content_type, progress);
34234}
34235inline Result Client::Post(const std::string &path, const Headers &headers,
34236 const std::string &body,
34237 const std::string &content_type) {
34238 return cli_->Post(path, headers, body, content_type);
34239}
34240
34241inline Result Client::Post(const std::string &path, const Headers &headers,
34242 const std::string &body,
34243 const std::string &content_type,
34244 ContentReceiver content_receiver) {
34245 return cli_->Post(path, headers, body, content_type, std::move(content_receiver));
34246}
34247inline Result Client::Post(const std::string &path, const Headers &headers,
34248 const std::string &body,
34249 const std::string &content_type, Progress progress) {
34250 return cli_->Post(path, headers, body, content_type, progress);
34251}
34252inline Result Client::Post(const std::string &path, size_t content_length,
34253 ContentProvider content_provider,
34254 const std::string &content_type) {
34255 return cli_->Post(path, content_length, std::move(content_provider),
34256 content_type);
34257}
34258inline Result Client::Post(const std::string &path,
34259 ContentProviderWithoutLength content_provider,
34260 const std::string &content_type) {
34261 return cli_->Post(path, std::move(content_provider), content_type);
34262}
34263inline Result Client::Post(const std::string &path, const Headers &headers,
34264 size_t content_length,
34265 ContentProvider content_provider,
34266 const std::string &content_type) {
34267 return cli_->Post(path, headers, content_length, std::move(content_provider),
34268 content_type);
34269}
34270inline Result Client::Post(const std::string &path, const Headers &headers,
34271 ContentProviderWithoutLength content_provider,
34272 const std::string &content_type) {
34273 return cli_->Post(path, headers, std::move(content_provider), content_type);
34274}
34275inline Result Client::Post(const std::string &path, const Params &params) {
34276 return cli_->Post(path, params);
34277}
34278inline Result Client::Post(const std::string &path, const Headers &headers,
34279 const Params &params) {
34280 return cli_->Post(path, headers, params);
34281}
34282inline Result Client::Post(const std::string &path, const Headers &headers,
34283 const Params &params, Progress progress) {
34284 return cli_->Post(path, headers, params, progress);
34285}
34286inline Result Client::Post(const std::string &path,
34287 const MultipartFormDataItems &items) {
34288 return cli_->Post(path, items);
34289}
34290inline Result Client::Post(const std::string &path, const Headers &headers,
34291 const MultipartFormDataItems &items) {
34292 return cli_->Post(path, headers, items);
34293}
34294inline Result Client::Post(const std::string &path, const Headers &headers,
34295 const MultipartFormDataItems &items,
34296 const std::string &boundary) {
34297 return cli_->Post(path, headers, items, boundary);
34298}
34299inline Result
34300Client::Post(const std::string &path, const Headers &headers,
34301 const MultipartFormDataItems &items,
34302 const MultipartFormDataProviderItems &provider_items) {
34303 return cli_->Post(path, headers, items, provider_items);
34304}
34305inline Result Client::Put(const std::string &path) { return cli_->Put(path); }
34306inline Result Client::Put(const std::string &path, const char *body,
34307 size_t content_length,
34308 const std::string &content_type) {
34309 return cli_->Put(path, body, content_length, content_type);
34310}
34311inline Result Client::Put(const std::string &path, const Headers &headers,
34312 const char *body, size_t content_length,
34313 const std::string &content_type) {
34314 return cli_->Put(path, headers, body, content_length, content_type);
34315}
34316inline Result Client::Put(const std::string &path, const Headers &headers,
34317 const char *body, size_t content_length,
34318 const std::string &content_type, Progress progress) {
34319 return cli_->Put(path, headers, body, content_length, content_type, progress);
34320}
34321inline Result Client::Put(const std::string &path, const std::string &body,
34322 const std::string &content_type) {
34323 return cli_->Put(path, body, content_type);
34324}
34325inline Result Client::Put(const std::string &path, const std::string &body,
34326 const std::string &content_type, Progress progress) {
34327 return cli_->Put(path, body, content_type, progress);
34328}
34329inline Result Client::Put(const std::string &path, const Headers &headers,
34330 const std::string &body,
34331 const std::string &content_type) {
34332 return cli_->Put(path, headers, body, content_type);
34333}
34334inline Result Client::Put(const std::string &path, const Headers &headers,
34335 const std::string &body,
34336 const std::string &content_type, Progress progress) {
34337 return cli_->Put(path, headers, body, content_type, progress);
34338}
34339inline Result Client::Put(const std::string &path, size_t content_length,
34340 ContentProvider content_provider,
34341 const std::string &content_type) {
34342 return cli_->Put(path, content_length, std::move(content_provider),
34343 content_type);
34344}
34345inline Result Client::Put(const std::string &path,
34346 ContentProviderWithoutLength content_provider,
34347 const std::string &content_type) {
34348 return cli_->Put(path, std::move(content_provider), content_type);
34349}
34350inline Result Client::Put(const std::string &path, const Headers &headers,
34351 size_t content_length,
34352 ContentProvider content_provider,
34353 const std::string &content_type) {
34354 return cli_->Put(path, headers, content_length, std::move(content_provider),
34355 content_type);
34356}
34357inline Result Client::Put(const std::string &path, const Headers &headers,
34358 ContentProviderWithoutLength content_provider,
34359 const std::string &content_type) {
34360 return cli_->Put(path, headers, std::move(content_provider), content_type);
34361}
34362inline Result Client::Put(const std::string &path, const Params &params) {
34363 return cli_->Put(path, params);
34364}
34365inline Result Client::Put(const std::string &path, const Headers &headers,
34366 const Params &params) {
34367 return cli_->Put(path, headers, params);
34368}
34369inline Result Client::Put(const std::string &path, const Headers &headers,
34370 const Params &params, Progress progress) {
34371 return cli_->Put(path, headers, params, progress);
34372}
34373inline Result Client::Put(const std::string &path,
34374 const MultipartFormDataItems &items) {
34375 return cli_->Put(path, items);
34376}
34377inline Result Client::Put(const std::string &path, const Headers &headers,
34378 const MultipartFormDataItems &items) {
34379 return cli_->Put(path, headers, items);
34380}
34381inline Result Client::Put(const std::string &path, const Headers &headers,
34382 const MultipartFormDataItems &items,
34383 const std::string &boundary) {
34384 return cli_->Put(path, headers, items, boundary);
34385}
34386inline Result
34387Client::Put(const std::string &path, const Headers &headers,
34388 const MultipartFormDataItems &items,
34389 const MultipartFormDataProviderItems &provider_items) {
34390 return cli_->Put(path, headers, items, provider_items);
34391}
34392inline Result Client::Patch(const std::string &path) {
34393 return cli_->Patch(path);
34394}
34395inline Result Client::Patch(const std::string &path, const char *body,
34396 size_t content_length,
34397 const std::string &content_type) {
34398 return cli_->Patch(path, body, content_length, content_type);
34399}
34400inline Result Client::Patch(const std::string &path, const char *body,
34401 size_t content_length,
34402 const std::string &content_type, Progress progress) {
34403 return cli_->Patch(path, body, content_length, content_type, progress);
34404}
34405inline Result Client::Patch(const std::string &path, const Headers &headers,
34406 const char *body, size_t content_length,
34407 const std::string &content_type) {
34408 return cli_->Patch(path, headers, body, content_length, content_type);
34409}
34410inline Result Client::Patch(const std::string &path, const Headers &headers,
34411 const char *body, size_t content_length,
34412 const std::string &content_type, Progress progress) {
34413 return cli_->Patch(path, headers, body, content_length, content_type, progress);
34414}
34415inline Result Client::Patch(const std::string &path, const std::string &body,
34416 const std::string &content_type) {
34417 return cli_->Patch(path, body, content_type);
34418}
34419inline Result Client::Patch(const std::string &path, const std::string &body,
34420 const std::string &content_type, Progress progress) {
34421 return cli_->Patch(path, body, content_type, progress);
34422}
34423inline Result Client::Patch(const std::string &path, const Headers &headers,
34424 const std::string &body,
34425 const std::string &content_type) {
34426 return cli_->Patch(path, headers, body, content_type);
34427}
34428inline Result Client::Patch(const std::string &path, const Headers &headers,
34429 const std::string &body,
34430 const std::string &content_type, Progress progress) {
34431 return cli_->Patch(path, headers, body, content_type, progress);
34432}
34433inline Result Client::Patch(const std::string &path, size_t content_length,
34434 ContentProvider content_provider,
34435 const std::string &content_type) {
34436 return cli_->Patch(path, content_length, std::move(content_provider),
34437 content_type);
34438}
34439inline Result Client::Patch(const std::string &path,
34440 ContentProviderWithoutLength content_provider,
34441 const std::string &content_type) {
34442 return cli_->Patch(path, std::move(content_provider), content_type);
34443}
34444inline Result Client::Patch(const std::string &path, const Headers &headers,
34445 size_t content_length,
34446 ContentProvider content_provider,
34447 const std::string &content_type) {
34448 return cli_->Patch(path, headers, content_length, std::move(content_provider),
34449 content_type);
34450}
34451inline Result Client::Patch(const std::string &path, const Headers &headers,
34452 ContentProviderWithoutLength content_provider,
34453 const std::string &content_type) {
34454 return cli_->Patch(path, headers, std::move(content_provider), content_type);
34455}
34456inline Result Client::Delete(const std::string &path) {
34457 return cli_->Delete(path);
34458}
34459inline Result Client::Delete(const std::string &path, const Headers &headers) {
34460 return cli_->Delete(path, headers);
34461}
34462inline Result Client::Delete(const std::string &path, const char *body,
34463 size_t content_length,
34464 const std::string &content_type) {
34465 return cli_->Delete(path, body, content_length, content_type);
34466}
34467inline Result Client::Delete(const std::string &path, const char *body,
34468 size_t content_length,
34469 const std::string &content_type, Progress progress) {
34470 return cli_->Delete(path, body, content_length, content_type, progress);
34471}
34472inline Result Client::Delete(const std::string &path, const Headers &headers,
34473 const char *body, size_t content_length,
34474 const std::string &content_type) {
34475 return cli_->Delete(path, headers, body, content_length, content_type);
34476}
34477inline Result Client::Delete(const std::string &path, const Headers &headers,
34478 const char *body, size_t content_length,
34479 const std::string &content_type, Progress progress) {
34480 return cli_->Delete(path, headers, body, content_length, content_type, progress);
34481}
34482inline Result Client::Delete(const std::string &path, const std::string &body,
34483 const std::string &content_type) {
34484 return cli_->Delete(path, body, content_type);
34485}
34486inline Result Client::Delete(const std::string &path, const std::string &body,
34487 const std::string &content_type, Progress progress) {
34488 return cli_->Delete(path, body, content_type, progress);
34489}
34490inline Result Client::Delete(const std::string &path, const Headers &headers,
34491 const std::string &body,
34492 const std::string &content_type) {
34493 return cli_->Delete(path, headers, body, content_type);
34494}
34495inline Result Client::Delete(const std::string &path, const Headers &headers,
34496 const std::string &body,
34497 const std::string &content_type, Progress progress) {
34498 return cli_->Delete(path, headers, body, content_type, progress);
34499}
34500inline Result Client::Options(const std::string &path) {
34501 return cli_->Options(path);
34502}
34503inline Result Client::Options(const std::string &path, const Headers &headers) {
34504 return cli_->Options(path, headers);
34505}
34506
34507inline bool Client::send(Request &req, Response &res, Error &error) {
34508 return cli_->send(req, res, error);
34509}
34510
34511inline Result Client::send(const Request &req) { return cli_->send(req); }
34512
34513inline void Client::stop() { cli_->stop(); }
34514
34515inline std::string Client::host() const { return cli_->host(); }
34516
34517inline int Client::port() const { return cli_->port(); }
34518
34519inline size_t Client::is_socket_open() const { return cli_->is_socket_open(); }
34520
34521inline socket_t Client::socket() const { return cli_->socket(); }
34522
34523inline void
34524Client::set_hostname_addr_map(std::map<std::string, std::string> addr_map) {
34525 cli_->set_hostname_addr_map(std::move(addr_map));
34526}
34527
34528inline void Client::set_default_headers(Headers headers) {
34529 cli_->set_default_headers(std::move(headers));
34530}
34531
34532inline void Client::set_header_writer(
34533 std::function<ssize_t(Stream &, Headers &)> const &writer) {
34534 cli_->set_header_writer(writer);
34535}
34536
34537inline void Client::set_address_family(int family) {
34538 cli_->set_address_family(family);
34539}
34540
34541inline void Client::set_tcp_nodelay(bool on) { cli_->set_tcp_nodelay(on); }
34542
34543inline void Client::set_socket_options(SocketOptions socket_options) {
34544 cli_->set_socket_options(std::move(socket_options));
34545}
34546
34547inline void Client::set_connection_timeout(time_t sec, time_t usec) {
34548 cli_->set_connection_timeout(sec, usec);
34549}
34550
34551inline void Client::set_read_timeout(time_t sec, time_t usec) {
34552 cli_->set_read_timeout(sec, usec);
34553}
34554
34555inline void Client::set_write_timeout(time_t sec, time_t usec) {
34556 cli_->set_write_timeout(sec, usec);
34557}
34558
34559inline void Client::set_basic_auth(const std::string &username,
34560 const std::string &password) {
34561 cli_->set_basic_auth(username, password);
34562}
34563inline void Client::set_bearer_token_auth(const std::string &token) {
34564 cli_->set_bearer_token_auth(token);
34565}
34566#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
34567inline void Client::set_digest_auth(const std::string &username,
34568 const std::string &password) {
34569 cli_->set_digest_auth(username, password);
34570}
34571#endif
34572
34573inline void Client::set_keep_alive(bool on) { cli_->set_keep_alive(on); }
34574inline void Client::set_follow_location(bool on) {
34575 cli_->set_follow_location(on);
34576}
34577
34578inline void Client::set_url_encode(bool on) { cli_->set_url_encode(on); }
34579
34580inline void Client::set_compress(bool on) { cli_->set_compress(on); }
34581
34582inline void Client::set_decompress(bool on) { cli_->set_decompress(on); }
34583
34584inline void Client::set_interface(const std::string &intf) {
34585 cli_->set_interface(intf);
34586}
34587
34588inline void Client::set_proxy(const std::string &host, int port) {
34589 cli_->set_proxy(host, port);
34590}
34591inline void Client::set_proxy_basic_auth(const std::string &username,
34592 const std::string &password) {
34593 cli_->set_proxy_basic_auth(username, password);
34594}
34595inline void Client::set_proxy_bearer_token_auth(const std::string &token) {
34596 cli_->set_proxy_bearer_token_auth(token);
34597}
34598#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
34599inline void Client::set_proxy_digest_auth(const std::string &username,
34600 const std::string &password) {
34601 cli_->set_proxy_digest_auth(username, password);
34602}
34603#endif
34604
34605#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
34606inline void Client::enable_server_certificate_verification(bool enabled) {
34607 cli_->enable_server_certificate_verification(enabled);
34608}
34609#endif
34610
34611inline void Client::set_logger(Logger logger) {
34612 cli_->set_logger(std::move(logger));
34613}
34614
34615#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
34616inline void Client::set_ca_cert_path(const std::string &ca_cert_file_path,
34617 const std::string &ca_cert_dir_path) {
34618 cli_->set_ca_cert_path(ca_cert_file_path, ca_cert_dir_path);
34619}
34620
34621inline void Client::set_ca_cert_store(X509_STORE *ca_cert_store) {
34622 if (is_ssl_) {
34623 static_cast<SSLClient &>(*cli_).set_ca_cert_store(ca_cert_store);
34624 } else {
34625 cli_->set_ca_cert_store(ca_cert_store);
34626 }
34627}
34628
34629inline void Client::load_ca_cert_store(const char *ca_cert, std::size_t size) {
34630 set_ca_cert_store(cli_->create_ca_cert_store(ca_cert, size));
34631}
34632
34633inline long Client::get_openssl_verify_result() const {
34634 if (is_ssl_) {
34635 return static_cast<SSLClient &>(*cli_).get_openssl_verify_result();
34636 }
34637 return -1; // NOTE: -1 doesn't match any of X509_V_ERR_???
34638}
34639
34640inline SSL_CTX *Client::ssl_context() const {
34641 if (is_ssl_) { return static_cast<SSLClient &>(*cli_).ssl_context(); }
34642 return nullptr;
34643}
34644#endif
34645
34646// ----------------------------------------------------------------------------
34647
34648} // namespace httplib
34649
34650#if defined(_WIN32) && defined(CPPHTTPLIB_USE_POLL)
34651#undef poll
34652#endif
34653
34654#endif // CPPHTTPLIB_HTTPLIB_H
34655
34656
34657
34658#ifndef _MACARON_BASE64_H_
34659#define _MACARON_BASE64_H_
34660
34685#include <cstdint>
34686#include <string>
34687
34688namespace macaron {
34689
34690class Base64 {
34691public:
34692 static std::string Encode(const std::string &data) {
34693 static constexpr char sEncodingTable[] = {
34694 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
34695 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
34696 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
34697 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
34698 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
34699
34700 size_t in_len = data.size();
34701 size_t out_len = 4 * ((in_len + 2) / 3);
34702 std::string ret(out_len, '\0');
34703 size_t i;
34704 char *p = const_cast<char *>(ret.c_str());
34705
34706 for (i = 0; in_len > 2 && i < in_len - 2; i += 3) {
34707 *p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
34708 *p++ = sEncodingTable[((data[i] & 0x3) << 4) |
34709 ((int)(data[i + 1] & 0xF0) >> 4)];
34710 *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) |
34711 ((int)(data[i + 2] & 0xC0) >> 6)];
34712 *p++ = sEncodingTable[data[i + 2] & 0x3F];
34713 }
34714 if (i < in_len) {
34715 *p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
34716 if (i == (in_len - 1)) {
34717 *p++ = sEncodingTable[((data[i] & 0x3) << 4)];
34718 *p++ = '=';
34719 } else {
34720 *p++ = sEncodingTable[((data[i] & 0x3) << 4) |
34721 ((int)(data[i + 1] & 0xF0) >> 4)];
34722 *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)];
34723 }
34724 *p++ = '=';
34725 }
34726
34727 return ret;
34728 }
34729
34730 static std::string Decode(const std::string &input, std::string &out) {
34731 static constexpr unsigned char kDecodingTable[] = {
34732 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
34733 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
34734 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, 52, 53, 54, 55, 56, 57,
34735 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6,
34736 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
34737 25, 64, 64, 64, 64, 64, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
34738 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64,
34739 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
34740 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
34741 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
34742 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
34743 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
34744 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
34745 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
34746 64, 64, 64, 64};
34747
34748 size_t in_len = input.size();
34749 if (in_len % 4 != 0)
34750 return "Input data size is not a multiple of 4";
34751
34752 size_t out_len = in_len / 4 * 3;
34753 if (in_len >= 1 && input[in_len - 1] == '=')
34754 out_len--;
34755 if (in_len >= 2 && input[in_len - 2] == '=')
34756 out_len--;
34757
34758 out.resize(out_len);
34759
34760 for (size_t i = 0, j = 0; i < in_len;) {
34761 uint32_t a = input[i] == '='
34762 ? 0 & i++
34763 : kDecodingTable[static_cast<int>(input[i++])];
34764 uint32_t b = input[i] == '='
34765 ? 0 & i++
34766 : kDecodingTable[static_cast<int>(input[i++])];
34767 uint32_t c = input[i] == '='
34768 ? 0 & i++
34769 : kDecodingTable[static_cast<int>(input[i++])];
34770 uint32_t d = input[i] == '='
34771 ? 0 & i++
34772 : kDecodingTable[static_cast<int>(input[i++])];
34773
34774 uint32_t triple =
34775 (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6);
34776
34777 if (j < out_len)
34778 out[j++] = (triple >> 2 * 8) & 0xFF;
34779 if (j < out_len)
34780 out[j++] = (triple >> 1 * 8) & 0xFF;
34781 if (j < out_len)
34782 out[j++] = (triple >> 0 * 8) & 0xFF;
34783 }
34784
34785 return "";
34786 }
34787};
34788
34789} // namespace macaron
34790
34791#endif /* _MACARON_BASE64_H_ */
34792
34793
34794#ifndef OLLAMA_HPP
34795#define OLLAMA_HPP
34796
34797/* MIT License
34798
34799 Copyright (c) 2025 James Montgomery (jmont)
34800
34801 Permission is hereby granted, free of charge, to any person obtaining a copy
34802 of this software and associated documentation files (the "Software"), to deal
34803 in the Software without restriction, including without limitation the rights
34804 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34805 copies of the Software, and to permit persons to whom the Software is
34806 furnished to do so, subject to the following conditions:
34807
34808 The above copyright notice and this permission notice shall be included in all
34809 copies or substantial portions of the Software.
34810
34811 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34812 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34813 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34814 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34815 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34816 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
34817 SOFTWARE.
34818*/
34819
34820/* About this software:
34821
34822 Ollama is a high-quality REST server and API providing an interface to run
34823 language models locally via llama.cpp.
34824
34825 Ollama was made by Jeffrey Morgan (@jmorganca) and the Ollama team and is
34826 available under the MIT License. To support this project or for more details
34827 go to https://github.com/ollama or https://ollama.com/.
34828
34829 This library is a header-only C++ integration of the Ollama API providing access
34830 to most API features while integrating them with std library classes or popular
34831 header-only libraries within the community. The following external libraries are
34832 used:
34833*/
34834
34835/*
34836 httplib is a header-only C++ http/https library.
34837 This library was created by Yuji Hirose and is available under the MIT License.
34838 For more details visit: https://github.com/yhirose/cpp-httplib
34839*/
34840
34841/*
34842 nlohmnann JSON is a feature-rich header-only C++ JSON implementation.
34843 This library was created by Niels Lohmann and is available under the MIT License.
34844 For more details visit: https://github.com/nlohmann/json
34845*/
34846
34847/*
34848 Base64.h is a header-only C++ library for encoding and decoding Base64 values.
34849 This library was created by tomykaira and is available under the MIT License.
34850 For more details visit:
34851 https://gist.github.com/tomykaira/f0fd86b6c73063283afe550bc5d77594
34852*/
34853
34854#include <string>
34855#include <memory>
34856#include <fstream>
34857#include <iostream>
34858#include <numeric>
34859#include <functional>
34860#include <exception>
34861#include <initializer_list>
34862
34863// Namespace types and classes
34864namespace ollama
34865{
34866 using json = nlohmann::json;
34867 using base64 = macaron::Base64;
34868
34869 static bool use_exceptions = true; // Change this to false to avoid throwing exceptions within the library.
34870 static bool log_requests = false; // Log raw requests to the Ollama server. Useful when debugging.
34871 static bool log_replies = false; // Log raw replies from the Ollama server. Useful when debugging.
34872
34873 static void allow_exceptions(bool enable) {use_exceptions = enable;}
34874 static void show_requests(bool enable) {log_requests = enable;}
34875 static void show_replies(bool enable) {log_replies = enable;}
34876
34877 enum class message_type { generation, chat, embedding };
34878
34879 class exception : public std::exception {
34880 private:
34881 std::string message;
34882
34883 public:
34884 exception(const std::string& msg) : message(msg) {}
34885 const char* what() const noexcept override { return message.c_str(); }
34886 };
34887
34888 class invalid_json_exception : public ollama::exception { public: using exception::exception; };
34889
34890 class image {
34891 public:
34892 image(const std::string base64_sequence, bool valid = true)
34893 {
34894 this->base64_sequence = base64_sequence; this->valid = valid;
34895 }
34896 ~image(){};
34897
34898 static image from_file(const std::string& filepath)
34899 {
34900 bool valid = true;
34901 std::ifstream file(filepath, std::ios::binary);
34902 if (!file) {
34903 if (ollama::use_exceptions) throw ollama::exception("Unable to open image file from path.");
34904 valid = false; return image("", valid);
34905 }
34906
34907 std::string file_contents((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
34908
34909 return image(macaron::Base64::Encode(file_contents), valid);
34910 }
34911
34912 static image from_base64_string(const std::string& base64_string)
34913 {
34914 return image(base64_string);
34915 }
34916
34917 const std::string as_base64_string() const
34918 {
34919 return base64_sequence;
34920 }
34921
34922 bool is_valid(){return valid;}
34923
34924 operator std::string() const { return base64_sequence; }
34925
34926 operator std::vector<ollama::image>() const { std::vector<ollama::image> images; images.push_back(*this); return images; }
34927 operator std::vector<std::string>() const { std::vector<std::string> images; images.push_back(*this); return images; }
34928
34929 private:
34930 std::string base64_sequence;
34931 bool valid;
34932 };
34933
34934 class images: public std::vector<std::string> {
34935
34936 public:
34937 images(): std::vector<std::string>(0)
34938 {
34939
34940 }
34941 images(const std::initializer_list<ollama::image>& list) {
34942 for (ollama::image value : list) {
34943 this->push_back(value);
34944 }
34945 }
34946 ~images(){};
34947 std::vector<std::string> to_strings()
34948 {
34949 std::vector<std::string> strings;
34950 for (auto it = this->begin(); it != this->end(); ++it)
34951 strings.push_back(*it);
34952
34953 return strings;
34954 }
34955
34956 };
34957
34958 class options: public json {
34959
34960 public:
34961 options(): json() { this->emplace( "options", nlohmann::json::object() ); }
34962
34963 nlohmann::json& operator[](const std::string& key)
34964 {
34965 if ( !this->at("options").contains(key) ) this->at("options").emplace( key, nlohmann::json::object() );
34966 return this->at("options").at(key);
34967 }
34968 nlohmann::json& operator[](const char* key) { return this->operator[](std::string(key)); };
34969
34970 const nlohmann::json& operator[](const std::string& key) const { return this->at("options").at(key); }
34971 const nlohmann::json& operator[](const char* key) const { return this->operator[](std::string(key)); };
34972
34973 };
34974
34975 class message: public json {
34976 public:
34977 message(const std::string& role, const std::string& content, const std::vector<ollama::image>& images): json() { (*this)["role"] = role; (*this)["content"] = content; (*this)["images"] = images; }
34978 message(const std::string& role, const std::string& content): json() { (*this)["role"] = role; (*this)["content"] = content; }
34979 message() : json() {}
34980 ~message() {}
34981
34982 std::string as_json_string() const { return this->dump(); }
34983
34984 operator std::string() const { return this->as_json_string(); }
34985
34986 };
34987
34988 class messages: public std::vector<message> {
34989
34990 public:
34991 messages(): std::vector<message>(0) {}
34992 messages(ollama::message message): messages() { this->push_back(message); }
34993
34994 messages(const std::initializer_list<message>& list) {
34995 for (message value : list) {
34996 this->push_back(value);
34997 }
34998 }
34999 ~messages(){};
35000 const std::vector<std::string> to_strings() const
35001 {
35002 std::vector<std::string> strings;
35003 for (auto it = this->begin(); it != this->end(); ++it)
35004 strings.push_back(*it);
35005
35006 return strings;
35007 }
35008
35009 const std::vector<json> to_json() const
35010 {
35011 std::vector<json> output;
35012 for (auto it = this->begin(); it != this->end(); ++it)
35013 output.push_back(*it);
35014 return output;
35015 }
35016
35017 operator std::vector<json>() const {return std::vector<json>();}
35018 operator std::vector<std::string>() const { return this->to_strings(); }
35019
35020 };
35021
35022 class request: public json {
35023
35024 public:
35025
35026 // Create a request for a generation.
35027 request(const std::string& model,const std::string& prompt, const json& options=nullptr, bool stream=false, const std::vector<std::string>& images=std::vector<std::string>()): request()
35028 {
35029 (*this)["model"] = model;
35030 (*this)["prompt"] = prompt;
35031 (*this)["stream"] = stream;
35032
35033 if (options!=nullptr) (*this)["options"] = options["options"];
35034 if (!images.empty()) (*this)["images"] = images;
35035
35036 type = message_type::generation;
35037 }
35038
35039 // Create a request for a chat completion.
35040 request(const std::string& model, const ollama::messages& messages, const json& options=nullptr, bool stream=false, const std::string& format="json", const std::string& keep_alive_duration="5m"): request()
35041 {
35042 (*this)["model"] = model;
35043 (*this)["messages"] = messages.to_json();
35044 (*this)["stream"] = stream;
35045
35046 if (options!=nullptr) (*this)["options"] = options["options"];
35047 (void)format; //(*this)["format"] = format; // Commented out as providing the format causes issues with some models.
35048 (*this)["keep_alive"] = keep_alive_duration;
35049 type = message_type::chat;
35050
35051 }
35052 // Request for a chat completion with a single message
35053 request(const std::string& model, const ollama::message& message, const json& options=nullptr, bool stream=false, const std::string& format="json", const std::string& keep_alive_duration="5m") :request(model, messages(message), options, stream, format, keep_alive_duration ){}
35054
35055 request(message_type type): request() { this->type = type; }
35056
35057 request(): json() {}
35058 ~request(){};
35059
35060 static ollama::request from_embedding(const std::string& model, const std::string& input, const json& options=nullptr, bool truncate=true, const std::string& keep_alive_duration="5m")
35061 {
35062 ollama::request request(message_type::embedding);
35063
35064 request["model"] = model;
35065 request["input"] = input;
35066 if (options!=nullptr) request["options"] = options["options"];
35067 request["truncate"] = truncate;
35068 request["keep_alive"] = keep_alive_duration;
35069
35070 return request;
35071 }
35072
35073 const message_type& get_type() const { return type; }
35074
35075 private:
35076
35077 message_type type;
35078 };
35079
35080 class response {
35081
35082 public:
35083
35084 response(const std::string& json_string, message_type type=message_type::generation): type(type)
35085 {
35086 this->json_string = json_string;
35087 try
35088 {
35089 json_data = json::parse(json_string);
35090
35091 if (type==message_type::generation && json_data.contains("response")) simple_string=json_data["response"].get<std::string>();
35092 else
35093 if (type==message_type::embedding && json_data.contains("embeddings")) simple_string=json_data["embeddings"].get<std::string>();
35094 else
35095 if (type==message_type::chat && json_data.contains("message")) simple_string=json_data["message"]["content"].get<std::string>();
35096
35097 if ( json_data.contains("error") ) error_string =json_data["error"].get<std::string>();
35098 }
35099 catch(...) { if (ollama::use_exceptions) throw ollama::invalid_json_exception("Unable to parse JSON string:"+this->json_string); valid = false; }
35100 }
35101
35102 response() {json_string = ""; valid = false;}
35103 ~response(){};
35104
35105 bool is_valid() const {return valid;};
35106
35107 const std::string& as_json_string() const
35108 {
35109 return json_string;
35110 }
35111
35112 const json& as_json() const
35113 {
35114 return json_data;
35115 }
35116
35117 const std::string& as_simple_string() const
35118 {
35119 return simple_string;
35120 }
35121
35122 bool has_error() const
35123 {
35124 if ( json_data.contains("error") ) return true;
35125 return false;
35126 }
35127
35128 const std::string& get_error() const
35129 {
35130 return error_string;
35131 }
35132
35133 friend std::ostream& operator<<(std::ostream& os, const ollama::response& response) { os << response.as_simple_string(); return os; }
35134
35135 const message_type& get_type() const
35136 {
35137 return type;
35138 }
35139
35140 //operator std::string() const { return this->as_simple_string(); }
35141 operator std::__cxx11::basic_string<char>() const { return this->as_simple_string(); }
35142 //const operator std::string() const { return this->as_simple_string(); }
35143
35144
35145 private:
35146
35147 std::string json_string;
35148 std::string simple_string;
35149 std::string error_string;
35150
35151 json json_data;
35152 message_type type;
35153 bool valid;
35154 };
35155
35156}
35157
35159{
35160 using json = nlohmann::json;
35161
35162 public:
35163
35164 Ollama(const std::string& url)
35165 {
35166 this->server_url = url;
35167 this->cli = new httplib::Client(url);
35168 this->setReadTimeout(120);
35169 }
35170
35171 Ollama(): Ollama("http://localhost:11434") {}
35172 ~Ollama() { delete this->cli; }
35173
35174 ollama::response generate(const std::string& model,const std::string& prompt, const ollama::response& context, const json& options=nullptr, const std::vector<std::string>& images=std::vector<std::string>())
35175 {
35176 ollama::request request(model, prompt, options, false, images);
35177 if ( context.as_json().contains("context") ) request["context"] = context.as_json()["context"];
35178 return generate(request);
35179 }
35180
35181 ollama::response generate(const std::string& model,const std::string& prompt, const json& options=nullptr, const std::vector<std::string>& images=std::vector<std::string>())
35182 {
35183 ollama::request request(model, prompt, options, false, images);
35184 return generate(request);
35185 }
35186
35187 // Generate a non-streaming reply as a string.
35188 ollama::response generate(ollama::request& request)
35189 {
35190 ollama::response response;
35191
35192 request["stream"] = false;
35193 std::string request_string = request.dump();
35194 if (ollama::log_requests) std::cout << request_string << std::endl;
35195
35196 if (auto res = this->cli->Post("/api/generate",request_string, "application/json"))
35197 {
35198 if (ollama::log_replies) std::cout << res->body << std::endl;
35199
35200 response = ollama::response(res->body);
35201 if ( response.has_error() ) { if (ollama::use_exceptions) throw ollama::exception("Ollama response returned error: "+response.get_error() ); }
35202
35203 }
35204 else
35205 {
35206 if (ollama::use_exceptions) throw ollama::exception("No response returned from server "+this->server_url+". Error was: "+httplib::to_string( res.error() ));
35207 }
35208
35209 return response;
35210 }
35211
35212 bool generate(const std::string& model,const std::string& prompt, ollama::response& context, std::function<bool(const ollama::response&)> on_receive_token, const json& options=nullptr, const std::vector<std::string>& images=std::vector<std::string>())
35213 {
35214 ollama::request request(model, prompt, options, true, images);
35215 if ( context.as_json().contains("context") ) request["context"] = context.as_json()["context"];
35216 return generate(request, on_receive_token);
35217 }
35218
35219 bool generate(const std::string& model,const std::string& prompt, std::function<bool(const ollama::response&)> on_receive_token, const json& options=nullptr, const std::vector<std::string>& images=std::vector<std::string>())
35220 {
35221 ollama::request request(model, prompt, options, true, images);
35222 return generate(request, on_receive_token);
35223 }
35224
35225
35226 // Generate a streaming reply where a user-defined callback function is invoked when each token is received.
35227 bool generate(ollama::request& request, std::function<bool(const ollama::response&)> on_receive_token)
35228 {
35229 request["stream"] = true;
35230
35231 std::string request_string = request.dump();
35232 if (ollama::log_requests) std::cout << request_string << std::endl;
35233
35234 std::shared_ptr<std::vector<std::string>> partial_responses = std::make_shared<std::vector<std::string>>();
35235
35236 auto stream_callback = [on_receive_token, partial_responses](const char *data, size_t data_length)->bool{
35237
35238 std::string message(data, data_length);
35239 bool continue_stream = true;
35240
35241 if (ollama::log_replies) std::cout << message << std::endl;
35242 try
35243 {
35244 partial_responses->push_back(message);
35245 std::string total_response = std::accumulate(partial_responses->begin(), partial_responses->end(), std::string(""));
35246 ollama::response response(total_response);
35247 partial_responses->clear();
35248 continue_stream = on_receive_token(response);
35249 }
35250 catch (const ollama::invalid_json_exception& e) { /* Partial response was received. Will do nothing and attempt to concatenate with the next response. */ }
35251
35252 return continue_stream;
35253 };
35254
35255 if (auto res = this->cli->Post("/api/generate", request_string, "application/json", stream_callback)) { return true; }
35256 else if (res.error()==httplib::Error::Canceled) { /* Request cancelled by user. */ return true; }
35257 else { if (ollama::use_exceptions) throw ollama::exception( "No response from server returned at URL "+this->server_url+" Error: "+httplib::to_string( res.error() ) ); }
35258
35259 return false;
35260 }
35261
35262 ollama::response chat(const std::string& model, const ollama::messages& messages, json options=nullptr, const std::string& format="json", const std::string& keep_alive_duration="5m")
35263 {
35264 ollama::request request(model, messages, options, false, format, keep_alive_duration);
35265 return chat(request);
35266 }
35267
35268
35269 // Generate a non-streaming reply as a string.
35270 ollama::response chat(ollama::request& request)
35271 {
35272 ollama::response response;
35273
35274 request["stream"] = false;
35275 std::string request_string = request.dump();
35276 if (ollama::log_requests) std::cout << request_string << std::endl;
35277
35278 if (auto res = this->cli->Post("/api/chat",request_string, "application/json"))
35279 {
35280 if (ollama::log_replies) std::cout << res->body << std::endl;
35281
35282 response = ollama::response(res->body, ollama::message_type::chat);
35283 if ( response.has_error() ) { if (ollama::use_exceptions) throw ollama::exception("Ollama response returned error: "+response.get_error() ); }
35284
35285 }
35286 else
35287 {
35288 if (ollama::use_exceptions) throw ollama::exception("No response returned from server "+this->server_url+". Error was: "+httplib::to_string( res.error() ));
35289 }
35290
35291 return response;
35292 }
35293
35294 bool chat(const std::string& model, const ollama::messages& messages, std::function<bool(const ollama::response&)> on_receive_token, const json& options=nullptr, const std::string& format="json", const std::string& keep_alive_duration="5m")
35295 {
35296 ollama::request request(model, messages, options, true, format, keep_alive_duration);
35297 return chat(request, on_receive_token);
35298 }
35299
35300
35301 bool chat(ollama::request& request, std::function<bool(const ollama::response&)> on_receive_token)
35302 {
35303 ollama::response response;
35304 request["stream"] = true;
35305
35306 std::string request_string = request.dump();
35307 if (ollama::log_requests) std::cout << request_string << std::endl;
35308
35309 std::shared_ptr<std::vector<std::string>> partial_responses = std::make_shared<std::vector<std::string>>();
35310
35311 auto stream_callback = [on_receive_token, partial_responses](const char *data, size_t data_length)->bool{
35312
35313 std::string message(data, data_length);
35314 bool continue_stream = true;
35315
35316 if (ollama::log_replies) std::cout << message << std::endl;
35317 try
35318 {
35319 partial_responses->push_back(message);
35320 std::string total_response = std::accumulate(partial_responses->begin(), partial_responses->end(), std::string(""));
35321 ollama::response response(total_response, ollama::message_type::chat);
35322 partial_responses->clear();
35323
35324 if ( response.has_error() ) { if (ollama::use_exceptions) throw ollama::exception("Ollama response returned error: "+response.get_error() ); }
35325 continue_stream = on_receive_token(response);
35326 }
35327 catch (const ollama::invalid_json_exception& e) { /* Partial response was received. Will do nothing and attempt to concatenate with the next response. */ }
35328
35329 return continue_stream;
35330 };
35331
35332 if (auto res = this->cli->Post("/api/chat", request_string, "application/json", stream_callback)) { return true; }
35333 else if (res.error()==httplib::Error::Canceled) { /* Request cancelled by user. */ return true; }
35334 else { if (ollama::use_exceptions) throw ollama::exception( "No response from server returned at URL"+this->server_url+" Error: "+httplib::to_string( res.error() ) ); }
35335
35336 return false;
35337 }
35338
35339 bool create_model(const std::string& modelName, const std::string& modelFile, bool loadFromFile=true)
35340 {
35341
35342 // Generate the JSON request
35343 json request;
35344 request["name"] = modelName;
35345
35346 if (loadFromFile)
35347 {
35348 // Open the file
35349 std::ifstream file(modelFile, std::ios::binary);
35350
35351 // Check if the file is open
35352 if (!file.is_open()) {
35353 if (ollama::use_exceptions) throw ollama::exception("Failed to open file "+modelFile);
35354 return false;
35355 }
35356
35357 // Read the entire file into a string using iterators
35358 std::string file_contents((std::istreambuf_iterator<char>(file)),
35359 std::istreambuf_iterator<char>());
35360
35361 request["modelFile"] = file_contents;
35362 }
35363 else request["modelFile"] = modelFile;
35364
35365 std::string request_string = request.dump();
35366 if (ollama::log_requests) std::cout << request_string << std::endl;
35367
35368 std::string response;
35369
35370 if (auto res = this->cli->Post("/api/create",request_string, "application/json"))
35371 {
35372 if (ollama::log_replies) std::cout << res->body << std::endl;
35373
35374 json chunk = json::parse(res->body);
35375 if (chunk["status"]=="success") return true;
35376 }
35377 else
35378 {
35379 if (ollama::use_exceptions) throw ollama::exception("No response returned: "+httplib::to_string( res.error() ) );
35380 }
35381
35382 return false;
35383
35384 }
35385
35386 bool load_model(const std::string& model)
35387 {
35388 json request;
35389 request["model"] = model;
35390 std::string request_string = request.dump();
35391 if (ollama::log_requests) std::cout << request_string << std::endl;
35392
35393 // Send a blank request with the model name to instruct ollama to load the model into memory.
35394 if (auto res = this->cli->Post("/api/generate", request_string, "application/json"))
35395 {
35396 if (ollama::log_replies) std::cout << res->body << std::endl;
35397 json response = json::parse(res->body);
35398 return response["done"];
35399 }
35400 else
35401 {
35402 if (ollama::use_exceptions) throw ollama::exception("No response returned from server when loading model: "+httplib::to_string( res.error() ) );
35403 }
35404
35405 // If we didn't get a response from the server indicating the model was created, return false.
35406 return false;
35407 }
35408
35409 bool is_running()
35410 {
35411 auto res = cli->Get("/");
35412 if (res) if (res->body=="Ollama is running") return true;
35413 return false;
35414 }
35415
35416 json list_model_json()
35417 {
35418 json models;
35419 if (auto res = cli->Get("/api/tags"))
35420 {
35421 if (ollama::log_replies) std::cout << res->body << std::endl;
35422 models = json::parse(res->body);
35423 }
35424 else { if (ollama::use_exceptions) throw ollama::exception("No response returned from server when querying model list: "+httplib::to_string( res.error() ) );}
35425
35426 return models;
35427 }
35428
35429 std::vector<std::string> list_models()
35430 {
35431 std::vector<std::string> models;
35432
35433 json json_response = list_model_json();
35434
35435 for (auto& model: json_response["models"])
35436 {
35437 models.push_back(model["name"]);
35438 }
35439
35440 return models;
35441 }
35442
35443 json running_model_json()
35444 {
35445 json models;
35446 if (auto res = cli->Get("/api/ps"))
35447 {
35448 if (ollama::log_replies) std::cout << res->body << std::endl;
35449 models = json::parse(res->body);
35450 }
35451 else { if (ollama::use_exceptions) throw ollama::exception("No response returned from server when querying running models: "+httplib::to_string( res.error() ) );}
35452
35453 return models;
35454 }
35455
35456 std::vector<std::string> list_running_models()
35457 {
35458 std::vector<std::string> models;
35459
35460 json json_response = running_model_json();
35461
35462 for (auto& model: json_response["models"])
35463 {
35464 models.push_back(model["name"]);
35465 }
35466
35467 return models;
35468 }
35469
35470 bool blob_exists(const std::string& digest)
35471 {
35472 if (auto res = cli->Head("/api/blobs/"+digest))
35473 {
35474 if (res->status==httplib::StatusCode::OK_200) return true;
35475 if (res->status==httplib::StatusCode::NotFound_404) return false;
35476 }
35477 else { if (ollama::use_exceptions) throw ollama::exception("No response returned from server when checking if blob exists: "+httplib::to_string( res.error() ) );}
35478
35479 return false;
35480 }
35481
35482 bool create_blob(const std::string& digest)
35483 {
35484 if (auto res = cli->Post("/api/blobs/"+digest))
35485 {
35486 if (res->status==httplib::StatusCode::Created_201) return true;
35487 if (res->status==httplib::StatusCode::BadRequest_400) { if (ollama::use_exceptions) throw ollama::exception("Received bad request (Code 400) from Ollama server when creating blob."); }
35488 }
35489 else { if (ollama::use_exceptions) throw ollama::exception("No response returned from server when creating blob: "+httplib::to_string( res.error() ) );}
35490
35491 return false;
35492
35493 }
35494
35495 json show_model_info(const std::string& model, bool verbose=false)
35496 {
35497 json request, response;
35498 request["name"] = model;
35499 if (verbose) request["verbose"] = true;
35500
35501 std::string request_string = request.dump();
35502 if (ollama::log_requests) std::cout << request_string << std::endl;
35503
35504 if (auto res = cli->Post("/api/show", request_string, "application/json"))
35505 {
35506 if (ollama::log_replies) std::cout << "Reply was " << res->body << std::endl;
35507 try
35508 {
35509 response = json::parse(res->body);
35510 }
35511 catch(...)
35512 { if (ollama::use_exceptions) throw ollama::exception("Received bad response from Ollama server when querying model info."); }
35513 }
35514 else { if (ollama::use_exceptions) throw ollama::exception("No response returned from server when querying model info: "+httplib::to_string( res.error() ) );}
35515
35516 return response;
35517 }
35518
35519 bool copy_model(const std::string& source_model, const std::string& dest_model)
35520 {
35521 json request;
35522 request["source"] = source_model;
35523 request["destination"] = dest_model;
35524
35525 std::string request_string = request.dump();
35526 if (ollama::log_requests) std::cout << request_string << std::endl;
35527
35528 if (auto res = cli->Post("/api/copy", request_string, "application/json"))
35529 {
35530 if (res->status==httplib::StatusCode::OK_200) return true;
35531 if (res->status==httplib::StatusCode::NotFound_404) { if (ollama::use_exceptions) throw ollama::exception("Source model not found when copying model (Code 404)."); }
35532 }
35533 else { if (ollama::use_exceptions) throw ollama::exception("No response returned from server when copying model: "+httplib::to_string( res.error() ) );}
35534
35535 return false;
35536 }
35537
35538 bool delete_model(const std::string& model)
35539 {
35540 json request;
35541 request["name"] = model;
35542
35543 std::string request_string = request.dump();
35544 if (ollama::log_requests) std::cout << request_string << std::endl;
35545
35546 if (auto res = cli->Delete("/api/delete", request_string, "application/json"))
35547 {
35548 if (res->status==httplib::StatusCode::OK_200) return true;
35549 if (res->status==httplib::StatusCode::NotFound_404) { if (ollama::use_exceptions) throw ollama::exception("Model not found when trying to delete (Code 404)."); }
35550 }
35551 else { if (ollama::use_exceptions) throw ollama::exception("No response returned from server when deleting model: "+httplib::to_string( res.error() ) );}
35552
35553 return false;
35554 }
35555
35556 bool pull_model(const std::string& model, bool allow_insecure = false)
35557 {
35558 json request, response;
35559 request["name"] = model;
35560 request["insecure"] = allow_insecure;
35561 request["stream"] = false;
35562
35563 std::string request_string = request.dump();
35564 if (ollama::log_requests) std::cout << request_string << std::endl;
35565
35566 if (auto res = cli->Post("/api/pull", request_string, "application/json"))
35567 {
35568 if (res->status==httplib::StatusCode::OK_200) return true;
35569 if (res->status==httplib::StatusCode::NotFound_404) { if (ollama::use_exceptions) throw ollama::exception("Model not found when trying to pull (Code 404)."); return false; }
35570
35571 response = json::parse(res->body);
35572 if ( response.contains("error") ) { if (ollama::use_exceptions) throw ollama::exception( "Error returned from ollama when pulling model: "+response["error"].get<std::string>() ); return false; }
35573 }
35574 else { if (ollama::use_exceptions) throw ollama::exception("No response returned from server when pulling model: "+httplib::to_string( res.error() ) );}
35575
35576 return false;
35577 }
35578
35579 bool push_model(const std::string& model, bool allow_insecure = false)
35580 {
35581 json request, response;
35582 request["name"] = model;
35583 request["insecure"] = allow_insecure;
35584 request["stream"] = false;
35585
35586 std::string request_string = request.dump();
35587 if (ollama::log_requests) std::cout << request_string << std::endl;
35588
35589 if (auto res = cli->Post("/api/push", request_string, "application/json"))
35590 {
35591 if (res->status==httplib::StatusCode::OK_200) return true;
35592 if (res->status==httplib::StatusCode::NotFound_404) { if (ollama::use_exceptions) throw ollama::exception("Model not found when trying to push (Code 404)."); return false; }
35593
35594 response = json::parse(res->body);
35595 if ( response.contains("error") ) { if (ollama::use_exceptions) throw ollama::exception( "Error returned from ollama when pushing model: "+response["error"].get<std::string>() ); return false; }
35596 }
35597 else { if (ollama::use_exceptions) throw ollama::exception("No response returned from server when pushing model: "+httplib::to_string( res.error() ) );}
35598
35599 return false;
35600 }
35601
35602 ollama::response generate_embeddings(const std::string& model, const std::string& input, const json& options=nullptr, bool truncate = true, const std::string& keep_alive_duration="5m")
35603 {
35604 ollama::request request = ollama::request::from_embedding(model, input, options, truncate, keep_alive_duration);
35605 return generate_embeddings(request);
35606 }
35607
35608
35609 ollama::response generate_embeddings(ollama::request& request)
35610 {
35611 ollama::response response;
35612
35613 std::string request_string = request.dump();
35614 if (ollama::log_requests) std::cout << request_string << std::endl;
35615
35616 if (auto res = cli->Post("/api/embed", request_string, "application/json"))
35617 {
35618 if (ollama::log_replies) std::cout << res->body << std::endl;
35619
35620
35621 if (res->status==httplib::StatusCode::OK_200) {response = ollama::response(res->body); return response; };
35622 if (res->status==httplib::StatusCode::NotFound_404) { if (ollama::use_exceptions) throw ollama::exception("Model not found when trying to push (Code 404)."); }
35623
35624 if ( response.has_error() ) { if (ollama::use_exceptions) throw ollama::exception( "Error returned from ollama when generating embeddings: "+response.get_error() ); }
35625 }
35626 else { if (ollama::use_exceptions) throw ollama::exception("No response returned from server when pushing model: "+httplib::to_string( res.error() ) );}
35627
35628 return response;
35629 }
35630
35631 std::string get_version()
35632 {
35633 std::string version;
35634
35635 auto res = this->cli->Get("/api/version");
35636
35637 if (res)
35638 {
35639 json response = json::parse(res->body);
35640 version = response["version"];
35641 }
35642 else
35643 {
35644 throw ollama::exception("Error retrieving version: "+res->status);
35645 }
35646
35647 return version;
35648
35649 }
35650
35651 void setServerURL(const std::string& server_url)
35652 {
35653 this->server_url = server_url;
35654 delete(this->cli);
35655 this->cli = new httplib::Client(server_url);
35656 }
35657
35658 void setReadTimeout(const int seconds)
35659 {
35660 this->cli->set_read_timeout(seconds);
35661 }
35662
35663 void setWriteTimeout(const int seconds)
35664 {
35665 this->cli->set_write_timeout(seconds);
35666 }
35667
35668 private:
35669
35670/*
35671 bool send_request(const ollama::request& request, std::function<bool(const ollama::response&)> on_receive_response=nullptr)
35672 {
35673
35674 return true;
35675 }
35676*/
35677
35678 std::string server_url;
35679 httplib::Client *cli;
35680
35681};
35682
35683// Functions associated with Ollama singleton
35684namespace ollama
35685{
35686 // Use directly from the namespace as a singleton
35687 static Ollama ollama;
35688
35689 inline void setServerURL(const std::string& server_url)
35690 {
35691 ollama.setServerURL(server_url);
35692 }
35693
35694 inline ollama::response generate(const std::string& model, const std::string& prompt, const json& options=nullptr, const std::vector<std::string>& images=std::vector<std::string>())
35695 {
35696 return ollama.generate(model, prompt, options, images);
35697 }
35698
35699 inline ollama::response generate(const std::string& model,const std::string& prompt, const ollama::response& context, const json& options=nullptr, const std::vector<std::string>& images=std::vector<std::string>())
35700 {
35701 return ollama.generate(model, prompt, context, options, images);
35702 }
35703
35704 inline ollama::response generate(ollama::request& request)
35705 {
35706 return ollama.generate(request);
35707 }
35708
35709 inline bool generate(const std::string& model,const std::string& prompt, std::function<bool(const ollama::response&)> on_receive_response, const json& options=nullptr, const std::vector<std::string>& images=std::vector<std::string>())
35710 {
35711 return ollama.generate(model, prompt, on_receive_response, options, images);
35712 }
35713
35714 inline bool generate(const std::string& model,const std::string& prompt, ollama::response& context, std::function<bool(const ollama::response&)> on_receive_response, const json& options=nullptr, const std::vector<std::string>& images=std::vector<std::string>())
35715 {
35716 return ollama.generate(model, prompt, context, on_receive_response, options, images);
35717 }
35718
35719 inline bool generate(ollama::request& request, std::function<bool(const ollama::response&)> on_receive_response)
35720 {
35721 return ollama.generate(request, on_receive_response);
35722 }
35723
35724 inline ollama::response chat(const std::string& model, const ollama::messages& messages, const json& options=nullptr, const std::string& format="json", const std::string& keep_alive_duration="5m")
35725 {
35726 return ollama.chat(model, messages, options, format, keep_alive_duration);
35727 }
35728
35729 inline ollama::response chat(ollama::request& request)
35730 {
35731 return ollama.chat(request);
35732 }
35733
35734 inline bool chat(const std::string& model, const ollama::messages& messages, std::function<bool(const ollama::response&)> on_receive_response, const json& options=nullptr, const std::string& format="json", const std::string& keep_alive_duration="5m")
35735 {
35736 return ollama.chat(model, messages, on_receive_response, options, format, keep_alive_duration);
35737 }
35738
35739 inline bool chat(ollama::request& request, std::function<bool(const ollama::response&)> on_receive_response)
35740 {
35741 return ollama.chat(request, on_receive_response);
35742 }
35743
35744 inline bool create(const std::string& modelName, const std::string& modelFile, bool loadFromFile=true)
35745 {
35746 return ollama.create_model(modelName, modelFile, loadFromFile);
35747 }
35748
35749 inline bool is_running()
35750 {
35751 return ollama.is_running();
35752 }
35753
35754 inline bool load_model(const std::string& model)
35755 {
35756 return ollama.load_model(model);
35757 }
35758
35759 inline std::string get_version()
35760 {
35761 return ollama.get_version();
35762 }
35763
35764 inline std::vector<std::string> list_models()
35765 {
35766 return ollama.list_models();
35767 }
35768
35769 inline json list_model_json()
35770 {
35771 return ollama.list_model_json();
35772 }
35773
35774 inline std::vector<std::string> list_running_models()
35775 {
35776 return ollama.list_running_models();
35777 }
35778
35779 inline json running_model_json()
35780 {
35781 return ollama.running_model_json();
35782 }
35783
35784 inline bool blob_exists(const std::string& digest)
35785 {
35786 return ollama.blob_exists(digest);
35787 }
35788
35789 inline bool create_blob(const std::string& digest)
35790 {
35791 return ollama.create_blob(digest);
35792 }
35793
35794 inline json show_model_info(const std::string& model, bool verbose=false)
35795 {
35796 return ollama.show_model_info(model, verbose);
35797 }
35798
35799 inline bool copy_model(const std::string& source_model, const std::string& dest_model)
35800 {
35801 return ollama.copy_model(source_model, dest_model);
35802 }
35803
35804 inline bool delete_model(const std::string& model)
35805 {
35806 return ollama.delete_model(model);
35807 }
35808
35809 inline bool pull_model(const std::string& model, bool allow_insecure = false)
35810 {
35811 return ollama.pull_model(model, allow_insecure);
35812 }
35813
35814 inline bool push_model(const std::string& model, bool allow_insecure = false)
35815 {
35816 return ollama.push_model(model, allow_insecure);
35817 }
35818
35819 inline ollama::response generate_embeddings(const std::string& model, const std::string& input, const json& options=nullptr, bool truncate = true, const std::string& keep_alive_duration="5m")
35820 {
35821 return ollama.generate_embeddings(model, input, options, truncate, keep_alive_duration);
35822 }
35823
35824 inline ollama::response generate_embeddings(ollama::request& request)
35825 {
35826 return ollama.generate_embeddings(request);
35827 }
35828
35829 inline void setReadTimeout(const int& seconds)
35830 {
35831 ollama.setReadTimeout(seconds);
35832 }
35833
35834 inline void setWriteTimeout(const int& seconds)
35835 {
35836 ollama.setWriteTimeout(seconds);
35837 }
35838
35839}
35840
35841
35842#endif
Definition ollama.hpp:35159
namespace for Niels Lohmann
Definition ollama.hpp:19424
constexpr bool is_string() const noexcept
return whether value is a string
Definition ollama.hpp:20696
number_integer_t * get_impl_ptr(number_integer_t *) noexcept
get a pointer to the value (integer number)
Definition ollama.hpp:20789
size_type erase(const typename object_t::key_type &key)
remove element from a JSON object given a key
Definition ollama.hpp:21929
reference operator[](KeyType &&key)
access specified object element
Definition ollama.hpp:21497
json_value(object_t &&value)
constructor for rvalue objects
Definition ollama.hpp:19859
size_type size() const noexcept
returns the number of elements
Definition ollama.hpp:22270
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json from_cbor(IteratorType first, IteratorType last, const bool strict=true, const bool allow_exceptions=true, const cbor_tag_handler_t tag_handler=cbor_tag_handler_t::error)
create a JSON value from an input in CBOR format
Definition ollama.hpp:23703
json_value(typename binary_t::container_type &&value)
constructor for rvalue binary arrays
Definition ollama.hpp:19871
static std::vector< std::uint8_t > to_bjdata(const basic_json &j, const bool use_size=false, const bool use_type=false)
create a BJData serialization of a given JSON value
Definition ollama.hpp:23635
number_unsigned_t number_unsigned
number (unsigned integer)
Definition ollama.hpp:19763
auto get() const noexcept(noexcept(std::declval< const basic_json_t & >().template get_impl< ValueType >(detail::priority_tag< 4 > {}))) -> decltype(std::declval< const basic_json_t & >().template get_impl< ValueType >(detail::priority_tag< 4 > {}))
get a (pointer) value (explicit)
Definition ollama.hpp:21069
const_iterator end() const noexcept
returns an iterator to one past the last element
Definition ollama.hpp:22127
reference back()
access the last element
Definition ollama.hpp:21733
basic_json(CompatibleType &&val) noexcept(noexcept(//NOLINT(bugprone-forwarding-reference-overload, bugprone-exception-escape) JSONSerializer< U >::to_json(std::declval< basic_json_t & >(), std::forward< CompatibleType >(val))))
create a JSON value from compatible types
Definition ollama.hpp:20160
number_float_t number_float
number (floating-point)
Definition ollama.hpp:19765
reverse_iterator rbegin() noexcept
returns an iterator to the reverse-beginning
Definition ollama.hpp:22143
basic_json patch(const basic_json &json_patch) const
applies a JSON patch to a copy of the current object
Definition ollama.hpp:24295
json_value(const array_t &value)
constructor for arrays
Definition ollama.hpp:19862
array_t * get_impl_ptr(array_t *) noexcept
get a pointer to the value (array)
Definition ollama.hpp:20753
JSON_HEDLEY_RETURNS_NON_NULL const char * type_name() const noexcept
return the type as string
Definition ollama.hpp:23483
const_reference front() const
access the first element
Definition ollama.hpp:21726
constexpr bool is_array() const noexcept
return whether value is an array
Definition ollama.hpp:20689
number_float_t * get_impl_ptr(number_float_t *) noexcept
get a pointer to the value (floating-point number)
Definition ollama.hpp:20813
void swap(reference other) noexcept(std::is_nothrow_move_constructible< value_t >::value &&std::is_nothrow_move_assignable< value_t >::value &&std::is_nothrow_move_constructible< json_value >::value &&//NOLINT(cppcoreguidelines-noexcept-swap, performance-noexcept-swap) std::is_nothrow_move_assignable< json_value >::value)
exchanges the values
Definition ollama.hpp:22787
ReturnType value(const json_pointer &ptr, ValueType &&default_value) const
access specified object element via JSON Pointer with default value
Definition ollama.hpp:21677
size_type count(KeyType &&key) const
returns the number of occurrences of a key in a JSON object
Definition ollama.hpp:22046
constexpr const number_integer_t * get_impl_ptr(const number_integer_t *) const noexcept
get a pointer to the value (integer number)
Definition ollama.hpp:20795
iter_impl< const basic_json > const_iterator
a const iterator for a basic_json container
Definition ollama.hpp:19555
static void to_bjdata(const basic_json &j, detail::output_adapter< char > o, const bool use_size=false, const bool use_type=false)
create a BJData serialization of a given JSON value
Definition ollama.hpp:23654
std::initializer_list< detail::json_ref< basic_json > > initializer_list_t
helper type for initializer lists of basic_json values
Definition ollama.hpp:19499
constexpr bool is_number_integer() const noexcept
return whether value is an integer number
Definition ollama.hpp:20661
json_reverse_iterator< typename basic_json::const_iterator > const_reverse_iterator
a const reverse iterator for a basic_json container
Definition ollama.hpp:19559
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json from_bson(IteratorType first, IteratorType last, const bool strict=true, const bool allow_exceptions=true)
create a JSON value from an input in BSON format
Definition ollama.hpp:23898
basic_json get_impl(detail::priority_tag< 3 >) const
get special-case overload
Definition ollama.hpp:21021
static void to_bjdata(const basic_json &j, detail::output_adapter< std::uint8_t > o, const bool use_size=false, const bool use_type=false)
create a BJData serialization of a given JSON value
Definition ollama.hpp:23646
reference operator[](const json_pointer &ptr)
access specified element via JSON Pointer
Definition ollama.hpp:23943
typename std::allocator_traits< allocator_type >::const_pointer const_pointer
the type of an element const pointer
Definition ollama.hpp:19550
static JSON_HEDLEY_RETURNS_NON_NULL T * create(Args &&... args)
helper for exception-safe object creation
Definition ollama.hpp:19703
std::size_t size_type
a type to represent container sizes
Definition ollama.hpp:19542
constexpr bool is_structured() const noexcept
return whether type is structured
Definition ollama.hpp:20633
json_value(boolean_t v) noexcept
constructor for booleans
Definition ollama.hpp:19770
const_reference operator[](KeyType &&key) const
access specified object element
Definition ollama.hpp:21521
boolean_t get_impl(boolean_t *) const
get a boolean (explicit)
Definition ollama.hpp:20730
void swap(binary_t &other)
exchanges the values
Definition ollama.hpp:22864
ReferenceType get_ref()
get a reference value (implicit)
Definition ollama.hpp:21159
size_type max_size() const noexcept
returns the maximum possible number of elements
Definition ollama.hpp:22309
void update(const_reference j, bool merge_objects=false)
updates a JSON object from another object, overwriting existing keys
Definition ollama.hpp:22733
ReferenceType get_ref() const
get a reference value (implicit)
Definition ollama.hpp:21170
constexpr bool is_discarded() const noexcept
return whether value is discarded
Definition ollama.hpp:20710
reference operator+=(initializer_list_t init)
add an object to an object
Definition ollama.hpp:22525
void push_back(basic_json &&val)
add an object to an array
Definition ollama.hpp:22413
const_reference operator[](const typename object_t::key_type &key) const
access specified object element
Definition ollama.hpp:21466
iteration_proxy< const_iterator > items() const noexcept
helper to access iterator member functions in range-based for
Definition ollama.hpp:22215
json_value(number_integer_t v) noexcept
constructor for numbers (integer)
Definition ollama.hpp:19772
static ReferenceType get_ref_impl(ThisType &obj)
helper function to implement get_ref()
Definition ollama.hpp:20848
const_reference back() const
access the last element
Definition ollama.hpp:21742
IteratorType erase(IteratorType first, IteratorType last)
remove elements given an iterator range
Definition ollama.hpp:21824
reference operator+=(const basic_json &val)
add an object to an array
Definition ollama.hpp:22470
friend void swap(reference left, reference right) noexcept(std::is_nothrow_move_constructible< value_t >::value &&std::is_nothrow_move_assignable< value_t >::value &&std::is_nothrow_move_constructible< json_value >::value &&//NOLINT(cppcoreguidelines-noexcept-swap, performance-noexcept-swap) std::is_nothrow_move_assignable< json_value >::value)
exchanges the values
Definition ollama.hpp:22804
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json from_ubjson(InputType &&i, const bool strict=true, const bool allow_exceptions=true)
create a JSON value from an input in UBJSON format
Definition ollama.hpp:23799
constexpr const string_t * get_impl_ptr(const string_t *) const noexcept
get a pointer to the value (string)
Definition ollama.hpp:20771
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json binary(const typename binary_t::container_type &init, typename binary_t::subtype_type subtype)
explicitly create a binary array (with subtype)
Definition ollama.hpp:20297
iterator insert(const_iterator pos, size_type cnt, const basic_json &val)
inserts copies of element into array
Definition ollama.hpp:22637
object_t * get_impl_ptr(object_t *) noexcept
get a pointer to the value (object)
Definition ollama.hpp:20741
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json from_bson(InputType &&i, const bool strict=true, const bool allow_exceptions=true)
create a JSON value from an input in BSON format
Definition ollama.hpp:23883
static allocator_type get_allocator()
returns the allocator associated with the container
Definition ollama.hpp:19565
nlohmann::byte_container_with_subtype< BinaryType > binary_t
a type for a packed binary type
Definition ollama.hpp:19690
reference at(KeyType &&key)
access specified object element with bounds checking
Definition ollama.hpp:21329
iterator end() noexcept
returns an iterator to one past the last element
Definition ollama.hpp:22118
constexpr bool is_number_unsigned() const noexcept
return whether value is an unsigned integer number
Definition ollama.hpp:20668
json_value(array_t &&value)
constructor for rvalue arrays
Definition ollama.hpp:19865
void update(const_iterator first, const_iterator last, bool merge_objects=false)
updates a JSON object from another object, overwriting existing keys
Definition ollama.hpp:22740
static std::vector< std::uint8_t > to_bson(const basic_json &j)
create a BSON serialization of a given JSON value
Definition ollama.hpp:23662
const_reverse_iterator rbegin() const noexcept
returns an iterator to the reverse-beginning
Definition ollama.hpp:22150
void push_back(initializer_list_t init)
add an object to an object
Definition ollama.hpp:22509
detail::parser_callback_t< basic_json > parser_callback_t
per-element parser callback type
Definition ollama.hpp:20127
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json object(initializer_list_t init={})
explicitly create an object from an initializer list
Definition ollama.hpp:20338
static void to_msgpack(const basic_json &j, detail::output_adapter< char > o)
create a MessagePack serialization of a given JSON value
Definition ollama.hpp:23601
iterator begin() noexcept
returns an iterator to the first element
Definition ollama.hpp:22093
array_t * array
array (stored with pointer to save storage)
Definition ollama.hpp:19753
void assert_invariant(bool check_parents=true) const noexcept
checks the class invariants
Definition ollama.hpp:20007
ReturnType value(const typename object_t::key_type &key, ValueType &&default_value) const
access specified object element with default value
Definition ollama.hpp:21576
ValueType get_impl(detail::priority_tag< 0 >) const noexcept(noexcept(JSONSerializer< ValueType >::from_json(std::declval< const basic_json_t & >(), std::declval< ValueType & >())))
get a value (explicit)
Definition ollama.hpp:20931
json_value(string_t &&value)
constructor for rvalue strings
Definition ollama.hpp:19853
const_iterator cend() const noexcept
returns an iterator to one past the last element
Definition ollama.hpp:22134
constexpr const binary_t * get_impl_ptr(const binary_t *) const noexcept
get a pointer to the value (binary)
Definition ollama.hpp:20831
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json from_bjdata(InputType &&i, const bool strict=true, const bool allow_exceptions=true)
create a JSON value from an input in BJData format
Definition ollama.hpp:23853
const_reference at(const json_pointer &ptr) const
access specified element via JSON Pointer
Definition ollama.hpp:23985
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json binary(typename binary_t::container_type &&init)
explicitly create a binary array
Definition ollama.hpp:20308
basic_json(std::nullptr_t=nullptr) noexcept
create a null object
Definition ollama.hpp:20148
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json from_cbor(InputType &&i, const bool strict=true, const bool allow_exceptions=true, const cbor_tag_handler_t tag_handler=cbor_tag_handler_t::error)
create a JSON value from an input in CBOR format
Definition ollama.hpp:23687
constexpr const number_unsigned_t * get_impl_ptr(const number_unsigned_t *) const noexcept
get a pointer to the value (unsigned number)
Definition ollama.hpp:20807
constexpr const boolean_t * get_impl_ptr(const boolean_t *) const noexcept
get a pointer to the value (boolean)
Definition ollama.hpp:20783
basic_json flatten() const
return flattened JSON value
Definition ollama.hpp:23999
constexpr const array_t * get_impl_ptr(const array_t *) const noexcept
get a pointer to the value (array)
Definition ollama.hpp:20759
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json from_ubjson(IteratorType first, IteratorType last, const bool strict=true, const bool allow_exceptions=true)
create a JSON value from an input in UBJSON format
Definition ollama.hpp:23814
json_value(number_unsigned_t v) noexcept
constructor for numbers (unsigned)
Definition ollama.hpp:19774
size_type erase(KeyType &&key)
remove element from a JSON object given a key
Definition ollama.hpp:21940
json_value(const string_t &value)
constructor for strings
Definition ollama.hpp:19850
const binary_t & get_binary() const
get a binary value
Definition ollama.hpp:21241
iterator insert(const_iterator pos, const_iterator first, const_iterator last)
inserts range of elements into array
Definition ollama.hpp:22657
void patch_inplace(const basic_json &json_patch)
applies a JSON patch in-place without copying the object
Definition ollama.hpp:24024
ReturnType value(KeyType &&key, ValueType &&default_value) const
access specified object element via JSON Pointer with default value
Definition ollama.hpp:21629
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json diff(const basic_json &source, const basic_json &target, const std::string &path="")
creates a diff as a JSON patch
Definition ollama.hpp:24305
const_reference operator[](const json_pointer &ptr) const
access specified element via JSON Pointer
Definition ollama.hpp:23957
json_value(number_float_t v) noexcept
constructor for numbers (floating-point)
Definition ollama.hpp:19776
ArrayType< basic_json, AllocatorType< basic_json > > array_t
a type for an array
Definition ollama.hpp:19666
bool contains(KeyType &&key) const
check the existence of an element in a JSON object
Definition ollama.hpp:22063
static void to_cbor(const basic_json &j, detail::output_adapter< std::uint8_t > o)
create a CBOR serialization of a given JSON value
Definition ollama.hpp:23571
static void to_bson(const basic_json &j, detail::output_adapter< char > o)
create a BSON serialization of a given JSON value
Definition ollama.hpp:23678
iterator find(const typename object_t::key_type &key)
find an element in a JSON object
Definition ollama.hpp:21976
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json binary(const typename binary_t::container_type &init)
explicitly create a binary array (without subtype)
Definition ollama.hpp:20286
BasicJsonType get_impl(detail::priority_tag< 2 >) const
get special-case overload
Definition ollama.hpp:20998
const_reference at(KeyType &&key) const
access specified object element with bounds checking
Definition ollama.hpp:21367
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json meta()
returns version information on the library
Definition ollama.hpp:19573
basic_json(size_type cnt, const basic_json &val)
construct an array with count copies of given value
Definition ollama.hpp:20345
const_iterator find(const typename object_t::key_type &key) const
find an element in a JSON object
Definition ollama.hpp:21990
static std::vector< std::uint8_t > to_cbor(const basic_json &j)
create a CBOR serialization of a given JSON value
Definition ollama.hpp:23562
IteratorType erase(IteratorType pos)
remove element given an iterator
Definition ollama.hpp:21754
iterator insert(const_iterator pos, const basic_json &val)
inserts element into array
Definition ollama.hpp:22610
NumberFloatType number_float_t
a type for a number (floating-point)
Definition ollama.hpp:19686
ValueType value(const typename object_t::key_type &key, const ValueType &default_value) const
access specified object element with default value
Definition ollama.hpp:21551
string_t * string
string (stored with pointer to save storage)
Definition ollama.hpp:19755
AllocatorType< basic_json > allocator_type
the allocator type
Definition ollama.hpp:19545
typename std::allocator_traits< allocator_type >::pointer pointer
the type of an element pointer
Definition ollama.hpp:19548
string_t dump(const int indent=-1, const char indent_char=' ', const bool ensure_ascii=false, const error_handler_t error_handler=error_handler_t::strict) const
serialization
Definition ollama.hpp:20597
void merge_patch(const basic_json &apply_patch)
applies a JSON Merge Patch
Definition ollama.hpp:24447
ValueType & get_to(ValueType &v) const noexcept(noexcept(JSONSerializer< ValueType >::from_json(std::declval< const basic_json_t & >(), v)))
get a value (explicit)
Definition ollama.hpp:21123
reference at(size_type idx)
access specified array element with bounds checking
Definition ollama.hpp:21263
iterator find(KeyType &&key)
find an element in a JSON object
Definition ollama.hpp:22006
binary_t * binary
binary (stored with pointer to save storage)
Definition ollama.hpp:19757
constexpr bool is_number_float() const noexcept
return whether value is a floating-point number
Definition ollama.hpp:20675
reverse_iterator rend() noexcept
returns an iterator to the reverse-end
Definition ollama.hpp:22157
static std::vector< std::uint8_t > to_ubjson(const basic_json &j, const bool use_size=false, const bool use_type=false)
create a UBJSON serialization of a given JSON value
Definition ollama.hpp:23608
reference at(const json_pointer &ptr)
access specified element via JSON Pointer
Definition ollama.hpp:23971
BooleanType boolean_t
a type for a boolean
Definition ollama.hpp:19674
std::less< StringType > default_object_comparator_t
default object key comparator type The actual object key comparator type (object_comparator_t) may be...
Definition ollama.hpp:19653
reference operator+=(const typename object_t::value_type &val)
add an object to an object
Definition ollama.hpp:22501
const_iterator cbegin() const noexcept
returns a const iterator to the first element
Definition ollama.hpp:22109
constexpr const number_float_t * get_impl_ptr(const number_float_t *) const noexcept
get a pointer to the value (floating-point number)
Definition ollama.hpp:20819
reference operator[](typename object_t::key_type key)
access specified object element
Definition ollama.hpp:21444
string_t * get_impl_ptr(string_t *) noexcept
get a pointer to the value (string)
Definition ollama.hpp:20765
constexpr auto get_ptr() const noexcept -> decltype(std::declval< const basic_json_t & >().get_impl_ptr(std::declval< PointerType >()))
get a pointer value (implicit)
Definition ollama.hpp:20881
~basic_json() noexcept
destructor
Definition ollama.hpp:20579
json_value(binary_t &&value)
constructor for rvalue binary arrays (internal type)
Definition ollama.hpp:19877
const_reverse_iterator crend() const noexcept
returns a const reverse iterator to one before the first
Definition ollama.hpp:22178
basic_json(initializer_list_t init, bool type_deduction=true, value_t manual_type=value_t::array)
create a container (array or object) from an initializer list
Definition ollama.hpp:20227
json_value(const object_t &value)
constructor for objects
Definition ollama.hpp:19856
void swap(typename binary_t::container_type &other)
exchanges the values
Definition ollama.hpp:22880
binary_t & get_binary()
get a binary value
Definition ollama.hpp:21229
const_iterator begin() const noexcept
returns an iterator to the first element
Definition ollama.hpp:22102
constexpr bool is_number() const noexcept
return whether value is a number
Definition ollama.hpp:20654
number_unsigned_t * get_impl_ptr(number_unsigned_t *) noexcept
get a pointer to the value (unsigned number)
Definition ollama.hpp:20801
void insert(const_iterator first, const_iterator last)
inserts range of elements into object
Definition ollama.hpp:22708
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json from_msgpack(InputType &&i, const bool strict=true, const bool allow_exceptions=true)
create a JSON value from an input in MessagePack format
Definition ollama.hpp:23745
auto get() noexcept -> decltype(std::declval< basic_json_t & >().template get_ptr< PointerType >())
get a pointer value (explicit)
Definition ollama.hpp:21110
reference operator[](size_type idx)
access specified array element
Definition ollama.hpp:21385
basic_json & operator=(basic_json other) noexcept(std::is_nothrow_move_constructible< value_t >::value &&std::is_nothrow_move_assignable< value_t >::value &&std::is_nothrow_move_constructible< json_value >::value &&std::is_nothrow_move_assignable< json_value >::value &&std::is_nothrow_move_assignable< json_base_class_t >::value)
copy assignment
Definition ollama.hpp:20556
static void to_ubjson(const basic_json &j, detail::output_adapter< char > o, const bool use_size=false, const bool use_type=false)
create a UBJSON serialization of a given JSON value
Definition ollama.hpp:23627
NumberIntegerType number_integer_t
a type for a number (integer)
Definition ollama.hpp:19678
auto get_ptr() noexcept -> decltype(std::declval< basic_json_t & >().get_impl_ptr(std::declval< PointerType >()))
get a pointer value (implicit)
Definition ollama.hpp:20870
const_reference at(const typename object_t::key_type &key) const
access specified object element with bounds checking
Definition ollama.hpp:21347
binary_t * get_impl_ptr(binary_t *) noexcept
get a pointer to the value (binary)
Definition ollama.hpp:20825
constexpr bool is_binary() const noexcept
return whether value is a binary array
Definition ollama.hpp:20703
void swap(object_t &other)
exchanges the values
Definition ollama.hpp:22832
constexpr auto get_impl(detail::priority_tag< 4 >) const noexcept -> decltype(std::declval< const basic_json_t & >().template get_ptr< PointerType >())
get a pointer value (explicit)
Definition ollama.hpp:21034
basic_json unflatten() const
unflatten a previously flattened JSON value
Definition ollama.hpp:24008
iterator insert(const_iterator pos, initializer_list_t ilist)
inserts elements from initializer list into array
Definition ollama.hpp:22688
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json binary(typename binary_t::container_type &&init, typename binary_t::subtype_type subtype)
explicitly create a binary array (with subtype)
Definition ollama.hpp:20319
iteration_proxy< iterator > items() noexcept
helper to access iterator member functions in range-based for
Definition ollama.hpp:22208
bool empty() const noexcept
checks whether the container is empty.
Definition ollama.hpp:22231
void swap(array_t &other)
exchanges the values
Definition ollama.hpp:22816
void erase(const size_type idx)
remove element from a JSON array given an index
Definition ollama.hpp:21947
reference operator+=(basic_json &&val)
add an object to an array
Definition ollama.hpp:22438
bool contains(const json_pointer &ptr) const
check the existence of an element in a JSON object given a JSON pointer
Definition ollama.hpp:22070
ValueType get_impl(detail::priority_tag< 1 >) const noexcept(noexcept(JSONSerializer< ValueType >::from_json(std::declval< const basic_json_t & >())))
get a value (explicit); special case
Definition ollama.hpp:20973
constexpr value_t type() const noexcept
return the type of the JSON value (explicit)
Definition ollama.hpp:20619
reference emplace_back(Args &&... args)
add an object to an array
Definition ollama.hpp:22534
ValueType value(const json_pointer &ptr, const ValueType &default_value) const
access specified object element via JSON Pointer with default value
Definition ollama.hpp:21652
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json array(initializer_list_t init={})
explicitly create an array from an initializer list
Definition ollama.hpp:20330
StringType string_t
a type for a string
Definition ollama.hpp:19670
ObjectType< StringType, basic_json, default_object_comparator_t, AllocatorType< std::pair< const StringType, basic_json > > > object_t
a type for an object
Definition ollama.hpp:19662
void push_back(const basic_json &val)
add an object to an array
Definition ollama.hpp:22446
ValueType value(KeyType &&key, const ValueType &default_value) const
access specified object element with default value
Definition ollama.hpp:21602
reference at(const typename object_t::key_type &key)
access specified object element with bounds checking
Definition ollama.hpp:21309
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json from_bjdata(IteratorType first, IteratorType last, const bool strict=true, const bool allow_exceptions=true)
create a JSON value from an input in BJData format
Definition ollama.hpp:23868
json_value m_value
the value of the current element
Definition ollama.hpp:23520
number_integer_t number_integer
number (integer)
Definition ollama.hpp:19761
const_reverse_iterator crbegin() const noexcept
returns a const reverse iterator to the last element
Definition ollama.hpp:22171
json_sax< basic_json > json_sax_t
SAX interface type, see nlohmann::json_sax.
Definition ollama.hpp:19503
constexpr bool is_boolean() const noexcept
return whether value is a boolean
Definition ollama.hpp:20647
size_type count(const typename object_t::key_type &key) const
returns the number of occurrences of a key in a JSON object
Definition ollama.hpp:22036
reference front()
access the first element
Definition ollama.hpp:21719
constexpr bool is_primitive() const noexcept
return whether type is primitive
Definition ollama.hpp:20626
constexpr bool is_null() const noexcept
return whether value is null
Definition ollama.hpp:20640
void clear() noexcept
clears the contents
Definition ollama.hpp:22352
constexpr const object_t * get_impl_ptr(const object_t *) const noexcept
get a pointer to the value (object)
Definition ollama.hpp:20747
json_value(value_t t)
constructor for empty values of a given type
Definition ollama.hpp:19778
static void to_ubjson(const basic_json &j, detail::output_adapter< std::uint8_t > o, const bool use_size=false, const bool use_type=false)
create a UBJSON serialization of a given JSON value
Definition ollama.hpp:23619
json_value()=default
default constructor (for null values)
basic_json(basic_json &&other) noexcept
move constructor
Definition ollama.hpp:20539
iter_impl< basic_json > iterator
an iterator for a basic_json container
Definition ollama.hpp:19553
basic_json(const value_t v)
create an empty value with a given type
Definition ollama.hpp:20140
const_reference operator[](size_type idx) const
access specified array element
Definition ollama.hpp:21431
std::ptrdiff_t difference_type
a type to represent differences between iterators
Definition ollama.hpp:19540
iterator insert(const_iterator pos, basic_json &&val)
inserts element into array
Definition ollama.hpp:22630
const_reverse_iterator rend() const noexcept
returns an iterator to the reverse-end
Definition ollama.hpp:22164
NumberUnsignedType number_unsigned_t
a type for a number (unsigned)
Definition ollama.hpp:19682
friend std::istream & operator>>(std::istream &i, basic_json &j)
deserialize from stream
Definition ollama.hpp:23468
static std::vector< std::uint8_t > to_msgpack(const basic_json &j)
create a MessagePack serialization of a given JSON value
Definition ollama.hpp:23585
void swap(string_t &other)
exchanges the values
Definition ollama.hpp:22848
basic_json(const BasicJsonType &val)
create a JSON value from an existing one
Definition ollama.hpp:20174
NLOHMANN_BASIC_JSON_TPL basic_json_t
workaround type for MSVC
Definition ollama.hpp:19449
boolean_t * get_impl_ptr(boolean_t *) noexcept
get a pointer to the value (boolean)
Definition ollama.hpp:20777
json_reverse_iterator< typename basic_json::iterator > reverse_iterator
a reverse iterator for a basic_json container
Definition ollama.hpp:19557
json_value(const binary_t &value)
constructor for binary arrays (internal type)
Definition ollama.hpp:19874
const_reference at(size_type idx) const
access specified array element with bounds checking
Definition ollama.hpp:21286
detail::actual_object_comparator_t< basic_json > object_comparator_t
object key comparator type
Definition ollama.hpp:19694
basic_json(const basic_json &other)
copy constructor
Definition ollama.hpp:20470
void push_back(const typename object_t::value_type &val)
add an object to an object
Definition ollama.hpp:22478
std::pair< iterator, bool > emplace(Args &&... args)
add an object to an object if key does not exist
Definition ollama.hpp:22559
static void to_cbor(const basic_json &j, detail::output_adapter< char > o)
create a CBOR serialization of a given JSON value
Definition ollama.hpp:23578
constexpr bool is_object() const noexcept
return whether value is an object
Definition ollama.hpp:20682
static void to_msgpack(const basic_json &j, detail::output_adapter< std::uint8_t > o)
create a MessagePack serialization of a given JSON value
Definition ollama.hpp:23594
static JSON_HEDLEY_WARN_UNUSED_RESULT basic_json from_msgpack(IteratorType first, IteratorType last, const bool strict=true, const bool allow_exceptions=true)
create a JSON value from an input in MessagePack format
Definition ollama.hpp:23760
iterator insert_iterator(const_iterator pos, Args &&... args)
Definition ollama.hpp:22591
basic_json(InputIT first, InputIT last)
construct a JSON container given an iterator range
Definition ollama.hpp:20357
bool contains(const typename object_t::key_type &key) const
check the existence of an element in a JSON object
Definition ollama.hpp:22054
static void to_bson(const basic_json &j, detail::output_adapter< std::uint8_t > o)
create a BSON serialization of a given JSON value
Definition ollama.hpp:23671
const_iterator find(KeyType &&key) const
find an element in a JSON object
Definition ollama.hpp:22022
boolean_t boolean
boolean
Definition ollama.hpp:19759
json_value(const typename binary_t::container_type &value)
constructor for binary arrays
Definition ollama.hpp:19868
::nlohmann::json_pointer< StringType > json_pointer
JSON Pointer, see nlohmann::json_pointer.
Definition ollama.hpp:19491
an internal type for a backed binary type
Definition ollama.hpp:5914
byte_container_with_subtype() noexcept(noexcept(container_type()))
Definition ollama.hpp:5920
byte_container_with_subtype(container_type &&b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b))))
Definition ollama.hpp:5942
byte_container_with_subtype(container_type &&b) noexcept(noexcept(container_type(std::move(b))))
Definition ollama.hpp:5930
constexpr subtype_type subtype() const noexcept
return the binary subtype
Definition ollama.hpp:5969
byte_container_with_subtype(const container_type &b, subtype_type subtype_) noexcept(noexcept(container_type(b)))
Definition ollama.hpp:5935
constexpr bool has_subtype() const noexcept
return whether the value has a subtype
Definition ollama.hpp:5976
byte_container_with_subtype(const container_type &b) noexcept(noexcept(container_type(b)))
Definition ollama.hpp:5925
void set_subtype(subtype_type subtype_) noexcept
sets the binary subtype
Definition ollama.hpp:5961
void clear_subtype() noexcept
clears the binary subtype
Definition ollama.hpp:5983
deserialization of CBOR, MessagePack, and UBJSON values
Definition ollama.hpp:9235
bool get_string(const input_format_t format, const NumberType len, string_t &result)
create a string by reading characters from the input
Definition ollama.hpp:11998
bool get_ubjson_size_type(std::pair< std::size_t, char_int_type > &result, bool inside_ndarray=false)
determine the type and size for a container
Definition ollama.hpp:11399
bool parse_bson_array()
Reads an array from the BSON input and passes it to the SAX-parser.
Definition ollama.hpp:9557
bool parse_bson_element_list(const bool is_array)
Read a BSON element list (as specified in the BSON-spec)
Definition ollama.hpp:9519
bool parse_msgpack_internal()
Definition ollama.hpp:10363
std::string get_token_string() const
Definition ollama.hpp:12068
bool get_msgpack_string(string_t &result)
reads a MessagePack string
Definition ollama.hpp:10744
std::string exception_message(const input_format_t format, const std::string &detail, const std::string &context) const
Definition ollama.hpp:12081
InputAdapterType ia
input adapter
Definition ollama.hpp:12121
bool get_binary(const input_format_t format, const NumberType len, binary_t &result)
create a byte array by reading bytes from the input
Definition ollama.hpp:12031
char_int_type get_ignore_noop()
Definition ollama.hpp:11928
bool get_ubjson_value(const char_int_type prefix)
Definition ollama.hpp:11466
bool get_ubjson_ndarray_size(std::vector< size_t > &dim)
Definition ollama.hpp:11111
bool parse_bson_element_internal(const char_int_type element_type, const std::size_t element_type_parse_position)
Read a BSON document element of the given element_type.
Definition ollama.hpp:9439
bool get_msgpack_object(const std::size_t len)
Definition ollama.hpp:10960
binary_reader(InputAdapterType &&adapter, const input_format_t format=input_format_t::json) noexcept
create a binary reader
Definition ollama.hpp:9251
bool parse_bson_internal()
Reads in a BSON-object and passes it to the SAX-parser.
Definition ollama.hpp:9335
bool get_cbor_object(const std::size_t len, const cbor_tag_handler_t tag_handler)
Definition ollama.hpp:10307
bool get_cbor_binary(binary_t &result)
reads a CBOR byte array
Definition ollama.hpp:10174
bool get_ubjson_array()
Definition ollama.hpp:11649
bool get_bson_cstr(string_t &result)
Parses a C-style string from the BSON input.
Definition ollama.hpp:9360
bool sax_parse(const input_format_t format, json_sax_t *sax_, const bool strict=true, const cbor_tag_handler_t tag_handler=cbor_tag_handler_t::error)
Definition ollama.hpp:9272
bool get_cbor_array(const std::size_t len, const cbor_tag_handler_t tag_handler)
Definition ollama.hpp:10269
bool get_msgpack_array(const std::size_t len)
Definition ollama.hpp:10938
char_int_type get()
get next character from the input
Definition ollama.hpp:11919
bool get_msgpack_binary(binary_t &result)
reads a MessagePack byte array
Definition ollama.hpp:10827
bool parse_ubjson_internal(const bool get_char=true)
Definition ollama.hpp:10997
bool get_ubjson_size_value(std::size_t &result, bool &is_ndarray, char_int_type prefix=0)
Definition ollama.hpp:11176
bool parse_cbor_internal(const bool get_char, const cbor_tag_handler_t tag_handler)
Definition ollama.hpp:9587
bool get_ubjson_object()
Definition ollama.hpp:11757
bool get_bson_string(const NumberType len, string_t &result)
Parses a zero-terminated string of length len from the BSON input.
Definition ollama.hpp:9390
bool get_ubjson_string(string_t &result, const bool get_char=true)
reads a UBJSON string
Definition ollama.hpp:11016
bool get_cbor_string(string_t &result)
reads a CBOR string
Definition ollama.hpp:10078
bool get_bson_binary(const NumberType len, binary_t &result)
Parses a byte array input of length len from the BSON input.
Definition ollama.hpp:9412
serialization to CBOR and MessagePack values
Definition ollama.hpp:15102
void write_bson_binary(const string_t &name, const binary_t &value)
Writes a BSON element with key name and binary value value.
Definition ollama.hpp:16211
void write_bson_boolean(const string_t &name, const bool value)
Writes a BSON element with key name and boolean value value.
Definition ollama.hpp:16049
void write_bson(const BasicJsonType &j)
Definition ollama.hpp:15122
void write_bson_integer(const string_t &name, const std::int64_t value)
Writes a BSON element with key name and integer value.
Definition ollama.hpp:16109
static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
Definition ollama.hpp:16127
void write_bson_array(const string_t &name, const typename BasicJsonType::array_t &value)
Writes a BSON element with key name and array value.
Definition ollama.hpp:16192
bool write_bjdata_ndarray(const typename BasicJsonType::object_t &value, const bool use_count, const bool use_type)
Definition ollama.hpp:16680
void write_bson_string(const string_t &name, const string_t &value)
Writes a BSON element with key name and string value value.
Definition ollama.hpp:16077
binary_writer(output_adapter_t< CharType > adapter)
create a binary writer
Definition ollama.hpp:15113
void write_bson_element(const string_t &name, const BasicJsonType &j)
Serializes the JSON value j to BSON and associates it with the key name.
Definition ollama.hpp:16274
void write_bson_object(const typename BasicJsonType::object_t &value)
Definition ollama.hpp:16336
void write_ubjson(const BasicJsonType &j, const bool use_count, const bool use_type, const bool add_prefix=true, const bool use_bjdata=false)
Definition ollama.hpp:15801
void write_bson_double(const string_t &name, const double value)
Writes a BSON element with key name and double value value.
Definition ollama.hpp:16059
static std::size_t calc_bson_string_size(const string_t &value)
Definition ollama.hpp:16069
static std::size_t calc_bson_entry_header_size(const string_t &name, const BasicJsonType &j)
Definition ollama.hpp:16022
void write_bson_null(const string_t &name)
Writes a BSON element with key name and null value.
Definition ollama.hpp:16091
CharType ubjson_prefix(const BasicJsonType &j, const bool use_bjdata) const noexcept
determine the type prefix of container values
Definition ollama.hpp:16566
void write_bson_unsigned(const string_t &name, const BasicJsonType &j)
Writes a BSON element with key name and unsigned value.
Definition ollama.hpp:16137
static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t &value)
Definition ollama.hpp:16184
static std::size_t calc_bson_element_size(const string_t &name, const BasicJsonType &j)
Calculates the size necessary to serialize the JSON value j with its name.
Definition ollama.hpp:16226
void write_msgpack(const BasicJsonType &j)
Definition ollama.hpp:15475
static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t &value)
Calculates the size of the BSON serialization of the given JSON-object j.
Definition ollama.hpp:16321
void write_cbor(const BasicJsonType &j)
Definition ollama.hpp:15151
void write_bson_entry_header(const string_t &name, const std::uint8_t element_type)
Writes the given element_type and name to the output adapter.
Definition ollama.hpp:16037
void write_bson_object_entry(const string_t &name, const typename BasicJsonType::object_t &value)
Writes a BSON element with key name and object value.
Definition ollama.hpp:16159
static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t &value)
Definition ollama.hpp:16169
static std::size_t calc_bson_integer_size(const std::int64_t value)
Definition ollama.hpp:16099
general exception of the basic_json class
Definition ollama.hpp:4395
const int id
the id of the exception
Definition ollama.hpp:4404
std::runtime_error m
an exception object as storage for error messages
Definition ollama.hpp:4487
const char * what() const noexcept override
returns the explanatory string
Definition ollama.hpp:4398
Definition ollama.hpp:6211
std::FILE * m_file
the file pointer to read from
Definition ollama.hpp:6236
Definition ollama.hpp:6249
std::istream * is
the associated input stream
Definition ollama.hpp:6295
exception indicating errors with iterators
Definition ollama.hpp:4546
a template for a bidirectional iterator for the basic_json class This class implements a both iterato...
Definition ollama.hpp:12939
iter_impl operator+(difference_type i) const
add to iterator
Definition ollama.hpp:13513
iter_impl & operator=(const iter_impl< typename std::remove_const< BasicJsonType >::type > &other) noexcept
converting assignment
Definition ollama.hpp:13076
bool operator>=(const iter_impl &other) const
comparison: greater than or equal
Definition ollama.hpp:13458
iter_impl(const iter_impl< typename std::remove_const< BasicJsonType >::type > &other) noexcept
converting constructor
Definition ollama.hpp:13066
bool operator<(const iter_impl &other) const
comparison: smaller
Definition ollama.hpp:13405
bool operator<=(const iter_impl &other) const
comparison: less than or equal
Definition ollama.hpp:13440
iter_impl & operator-=(difference_type i)
subtract from iterator
Definition ollama.hpp:13504
iter_impl & operator--()
pre-decrement (–it)
Definition ollama.hpp:13319
const object_t::key_type & key() const
return the key of an object iterator
Definition ollama.hpp:13613
bool operator==(const IterImpl &other) const
comparison: equal
Definition ollama.hpp:13360
iter_impl operator++(int) &
post-increment (it++)
Definition ollama.hpp:13257
iter_impl & operator+=(difference_type i)
add to iterator
Definition ollama.hpp:13467
reference operator[](difference_type n) const
access to successor
Definition ollama.hpp:13575
typename BasicJsonType::difference_type difference_type
a type to represent differences between iterators
Definition ollama.hpp:12969
pointer operator->() const
dereference the iterator
Definition ollama.hpp:13215
friend other_iter_impl
allow basic_json to access private members
Definition ollama.hpp:12943
internal_iterator< typename std::remove_const< BasicJsonType >::type > m_it
the actual iterator of the associated instance
Definition ollama.hpp:13638
difference_type operator-(const iter_impl &other) const
return difference
Definition ollama.hpp:13546
std::bidirectional_iterator_tag iterator_category
Definition ollama.hpp:12964
friend iter_impl operator+(difference_type i, const iter_impl &it)
addition of distance and iterator
Definition ollama.hpp:13524
reference value() const
return the value of an iterator
Definition ollama.hpp:13629
bool operator>(const iter_impl &other) const
comparison: greater than
Definition ollama.hpp:13449
typename std::conditional< std::is_const< BasicJsonType >::value, typename BasicJsonType::const_pointer, typename BasicJsonType::pointer >::type pointer
defines a pointer to the type iterated over (value_type)
Definition ollama.hpp:12973
iter_impl & operator++()
pre-increment (++it)
Definition ollama.hpp:13268
typename BasicJsonType::value_type value_type
the type of the values when the iterator is dereferenced
Definition ollama.hpp:12967
reference operator*() const
return a reference to the value pointed to by the iterator
Definition ollama.hpp:13171
iter_impl operator-(difference_type i) const
subtract from iterator
Definition ollama.hpp:13535
iter_impl< typename std::conditional< std::is_const< BasicJsonType >::value, typename std::remove_const< BasicJsonType >::type, const BasicJsonType >::type > other_iter_impl
the iterator with BasicJsonType of different const-ness
Definition ollama.hpp:12941
iter_impl & operator=(const iter_impl< const BasicJsonType > &other) noexcept
converting assignment
Definition ollama.hpp:13051
bool operator!=(const IterImpl &other) const
comparison: not equal
Definition ollama.hpp:13396
iter_impl operator--(int) &
post-decrement (it–)
Definition ollama.hpp:13308
typename std::conditional< std::is_const< BasicJsonType >::value, typename BasicJsonType::const_reference, typename BasicJsonType::reference >::type reference
defines a reference to the type iterated over (value_type)
Definition ollama.hpp:12978
iter_impl(const iter_impl< const BasicJsonType > &other) noexcept
const copy constructor
Definition ollama.hpp:13041
void set_end() noexcept
set the iterator past the last value
Definition ollama.hpp:13132
Definition ollama.hpp:5209
bool operator==(const iteration_proxy_value &o) const
equality operator (needed for InputIterator)
Definition ollama.hpp:5274
bool operator!=(const iteration_proxy_value &o) const
inequality operator (needed for range-based for)
Definition ollama.hpp:5280
string_type empty_str
an empty string (to return a reference for primitive values)
Definition ollama.hpp:5228
iteration_proxy_value & operator++()
increment operator (needed for range-based for)
Definition ollama.hpp:5257
std::size_t array_index_last
last stringified array index
Definition ollama.hpp:5224
std::size_t array_index
an index for arrays (used to create key names)
Definition ollama.hpp:5222
IteratorType::reference value() const
return value of the iterator
Definition ollama.hpp:5322
const string_type & key() const
return key of the iterator
Definition ollama.hpp:5286
string_type array_index_str
a string representation of the array index
Definition ollama.hpp:5226
IteratorType anchor
the iterator
Definition ollama.hpp:5220
proxy class for the items() function
Definition ollama.hpp:5330
IteratorType::pointer container
the container to iterate
Definition ollama.hpp:5333
iteration_proxy_value< IteratorType > end() const noexcept
return iterator end (needed for range-based for)
Definition ollama.hpp:5355
iteration_proxy_value< IteratorType > begin() const noexcept
return iterator begin (needed for range-based for)
Definition ollama.hpp:5349
iteration_proxy(typename IteratorType::reference cont) noexcept
construct iteration proxy from a container
Definition ollama.hpp:5339
Definition ollama.hpp:6304
Definition ollama.hpp:14843
a template for a reverse iterator class
Definition ollama.hpp:13692
json_reverse_iterator operator++(int) &
post-increment (it++)
Definition ollama.hpp:13708
json_reverse_iterator operator--(int) &
post-decrement (it–)
Definition ollama.hpp:13720
json_reverse_iterator & operator++()
pre-increment (++it)
Definition ollama.hpp:13714
json_reverse_iterator & operator+=(difference_type i)
add to iterator
Definition ollama.hpp:13732
reference operator[](difference_type n) const
access to successor
Definition ollama.hpp:13756
auto key() const -> decltype(std::declval< Base >().key())
return the key of an object iterator
Definition ollama.hpp:13762
difference_type operator-(const json_reverse_iterator &other) const
return difference
Definition ollama.hpp:13750
typename Base::reference reference
the reference type for the pointed-to element
Definition ollama.hpp:13698
reference value() const
return the value of an iterator
Definition ollama.hpp:13769
json_reverse_iterator(const base_iterator &it) noexcept
create reverse iterator from base class
Definition ollama.hpp:13705
json_reverse_iterator & operator--()
pre-decrement (–it)
Definition ollama.hpp:13726
std::reverse_iterator< Base > base_iterator
shortcut to the reverse iterator adapter
Definition ollama.hpp:13696
json_reverse_iterator operator-(difference_type i) const
subtract from iterator
Definition ollama.hpp:13744
json_reverse_iterator(const typename base_iterator::iterator_type &it) noexcept
create reverse iterator from iterator
Definition ollama.hpp:13701
json_reverse_iterator operator+(difference_type i) const
add to iterator
Definition ollama.hpp:13738
Definition ollama.hpp:7313
Definition ollama.hpp:7006
BasicJsonType & root
the parsed JSON value
Definition ollama.hpp:7292
std::pair< bool, BasicJsonType * > handle_value(Value &&v, const bool skip_callback=false)
Definition ollama.hpp:7228
SAX implementation to create a JSON value from SAX events.
Definition ollama.hpp:6823
json_sax_dom_parser(BasicJsonType &r, const bool allow_exceptions_=true)
Definition ollama.hpp:6836
JSON_HEDLEY_RETURNS_NON_NULL BasicJsonType * handle_value(Value &&v)
Definition ollama.hpp:6970
BasicJsonType & root
the parsed JSON value
Definition ollama.hpp:6993
Definition ollama.hpp:7430
JSON_HEDLEY_RETURNS_NON_NULL static JSON_HEDLEY_CONST const char * token_type_name(const token_type t) noexcept
return name of values of type token_type (only used for errors)
Definition ollama.hpp:7457
token_type
token types for the parser
Definition ollama.hpp:7434
lexical analysis
Definition ollama.hpp:7507
void reset() noexcept
reset token_buffer; current character is beginning of token
Definition ollama.hpp:8715
bool skip_bom()
skip the UTF-8 byte order mark
Definition ollama.hpp:8881
int get_codepoint()
get codepoint from 4 hex characters following \u
Definition ollama.hpp:7564
token_type scan_string()
scan a string literal
Definition ollama.hpp:7649
JSON_HEDLEY_RETURNS_NON_NULL constexpr const char * get_error_message() const noexcept
return syntax error message
Definition ollama.hpp:8868
std::string get_token_string() const
Definition ollama.hpp:8843
constexpr number_integer_t get_number_integer() const noexcept
return integer value
Definition ollama.hpp:8807
bool next_byte_in_range(std::initializer_list< char_int_type > ranges)
check if the next byte(s) are inside a given range
Definition ollama.hpp:7612
constexpr position_t get_position() const noexcept
return position of last read token
Definition ollama.hpp:8835
constexpr number_unsigned_t get_number_unsigned() const noexcept
return unsigned integer value
Definition ollama.hpp:8813
bool scan_comment()
scan a comment
Definition ollama.hpp:8239
InputAdapterType ia
input adapter
Definition ollama.hpp:8994
token_type scan_number()
scan a number literal
Definition ollama.hpp:8364
string_t & get_string()
return current string value (implicitly resets the token; useful only once)
Definition ollama.hpp:8825
void add(char_int_type c)
add a character to token_buffer
Definition ollama.hpp:8796
void unget()
unget current character (read it again on next get)
Definition ollama.hpp:8769
constexpr number_float_t get_number_float() const noexcept
return floating-point value
Definition ollama.hpp:8819
static JSON_HEDLEY_PURE char get_decimal_point() noexcept
return the locale-dependent decimal point
Definition ollama.hpp:7538
exception indicating other library errors
Definition ollama.hpp:4598
exception indicating access out of the defined range
Definition ollama.hpp:4581
Definition ollama.hpp:15060
output adapter for output streams
Definition ollama.hpp:15012
output adapter for basic_string
Definition ollama.hpp:15037
output adapter for byte vectors
Definition ollama.hpp:14987
exception indicating a parse error
Definition ollama.hpp:4493
static parse_error create(int id_, const position_t &pos, const std::string &what_arg, BasicJsonContext context)
create a parse error exception
Definition ollama.hpp:4505
const std::size_t byte
byte index of the parse error
Definition ollama.hpp:4530
syntax analysis
Definition ollama.hpp:12252
parser(InputAdapterType &&adapter, const parser_callback_t< BasicJsonType > cb=nullptr, const bool allow_exceptions_=true, const bool skip_comments=false)
a parser reading from an input adapter
Definition ollama.hpp:12262
void parse(const bool strict, BasicJsonType &result)
public parser interface
Definition ollama.hpp:12284
lexer_t m_lexer
the lexer
Definition ollama.hpp:12704
bool accept(const bool strict=true)
public accept interface
Definition ollama.hpp:12344
token_type get_token()
get next token from lexer
Definition ollama.hpp:12664
Definition ollama.hpp:12756
constexpr bool is_begin() const noexcept
return whether the iterator can be dereferenced
Definition ollama.hpp:12785
void set_end() noexcept
set iterator to a defined past the end
Definition ollama.hpp:12779
constexpr bool is_end() const noexcept
return whether the iterator is at end
Definition ollama.hpp:12791
void set_begin() noexcept
set iterator to a defined beginning
Definition ollama.hpp:12773
Definition ollama.hpp:18083
serializer(output_adapter_t< char > s, const char ichar, error_handler_t error_handler_=error_handler_t::strict)
Definition ollama.hpp:18098
const error_handler_t error_handler
error_handler how to react on decoding errors
Definition ollama.hpp:19015
string_t indent_string
the indentation string
Definition ollama.hpp:19012
const char indent_char
the indentation character
Definition ollama.hpp:19010
void dump(const BasicJsonType &val, const bool pretty_print, const bool ensure_ascii, const unsigned int indent_step, const unsigned int current_indent=0)
internal implementation of the serialization function
Definition ollama.hpp:18138
Definition ollama.hpp:6628
exception indicating executing a member function with a wrong type
Definition ollama.hpp:4564
Definition ollama.hpp:6463
std::array< std::char_traits< char >::int_type, 4 > utf8_bytes
a buffer for UTF-8 bytes
Definition ollama.hpp:6497
std::size_t utf8_bytes_filled
number of valid bytes in the utf8_codes array
Definition ollama.hpp:6502
std::size_t utf8_bytes_index
index to the utf8_codes array for the next valid byte
Definition ollama.hpp:6500
Definition ollama.hpp:25910
Definition ollama.hpp:26336
Definition ollama.hpp:25322
Definition ollama.hpp:25279
Definition ollama.hpp:25263
Definition ollama.hpp:25875
Definition ollama.hpp:25641
Definition ollama.hpp:25450
Definition ollama.hpp:25469
Definition ollama.hpp:25480
Definition ollama.hpp:27063
Definition ollama.hpp:30159
Definition ollama.hpp:25571
Definition ollama.hpp:29371
Definition ollama.hpp:25597
Definition ollama.hpp:25627
Definition ollama.hpp:27893
Definition ollama.hpp:27083
Definition ollama.hpp:27092
Definition ollama.hpp:27191
Definition ollama.hpp:27103
Definition ollama.hpp:27172
JSON Pointer defines a string syntax for identifying a specific value within a JSON document.
Definition ollama.hpp:13864
BasicJsonType & get_checked(BasicJsonType *ptr) const
Definition ollama.hpp:14250
friend json_pointer operator/(const json_pointer &lhs, string_t token)
create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
Definition ollama.hpp:13959
static BasicJsonType::size_type array_index(const string_t &s)
Definition ollama.hpp:14042
friend json_pointer operator/(const json_pointer &lhs, std::size_t array_idx)
create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
Definition ollama.hpp:13966
json_pointer(const string_t &s="")
create JSON pointer
Definition ollama.hpp:13890
static std::vector< string_t > split(const string_t &reference_string)
split the string input to reference tokens
Definition ollama.hpp:14494
bool empty() const noexcept
return whether pointer points to the root document
Definition ollama.hpp:14025
BasicJsonType & get_and_create(BasicJsonType &j) const
create and return a reference to the pointed to value
Definition ollama.hpp:14102
void pop_back()
remove last reference token
Definition ollama.hpp:13987
string_t to_string() const
return a string representation of the JSON pointer
Definition ollama.hpp:13896
json_pointer & operator/=(std::size_t array_idx)
append an array index at the end of this JSON pointer
Definition ollama.hpp:13944
void push_back(string_t &&token)
append an unescaped token at the end of the reference pointer
Definition ollama.hpp:14018
std::vector< string_t > reference_tokens
the reference tokens
Definition ollama.hpp:14753
static void flatten(const string_t &reference_string, const BasicJsonType &value, BasicJsonType &result)
Definition ollama.hpp:14563
json_pointer & operator/=(const json_pointer &ptr)
append another JSON pointer at the end of this JSON pointer
Definition ollama.hpp:13926
friend json_pointer operator/(const json_pointer &lhs, const json_pointer &rhs)
create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
Definition ollama.hpp:13951
BasicJsonType & get_unchecked(BasicJsonType *ptr) const
return a reference to the pointed to value
Definition ollama.hpp:14182
json_pointer parent_pointer() const
returns the parent of this JSON pointer
Definition ollama.hpp:13973
static BasicJsonType unflatten(const BasicJsonType &value)
Definition ollama.hpp:14635
json_pointer & operator/=(string_t token)
append an unescaped reference token at the end of this JSON pointer
Definition ollama.hpp:13936
const string_t & back() const
return last reference token
Definition ollama.hpp:13999
friend std::ostream & operator<<(std::ostream &o, const json_pointer &ptr)
write string representation of the JSON pointer to stream
Definition ollama.hpp:13917
const BasicJsonType & get_unchecked(const BasicJsonType *ptr) const
return a const reference to the pointed to value
Definition ollama.hpp:14308
void push_back(const string_t &token)
append an unescaped token at the end of the reference pointer
Definition ollama.hpp:14011
const BasicJsonType & get_checked(const BasicJsonType *ptr) const
Definition ollama.hpp:14357
bool contains(const BasicJsonType *ptr) const
Definition ollama.hpp:14406
Definition ollama.hpp:34690
Definition ollama.hpp:34879
Definition ollama.hpp:34890
Definition ollama.hpp:34934
Definition ollama.hpp:34888
Definition ollama.hpp:34975
Definition ollama.hpp:34988
Definition ollama.hpp:34958
Definition ollama.hpp:35022
Definition ollama.hpp:35080
int find_largest_pow10(const std::uint32_t n, std::uint32_t &pow10)
Definition ollama.hpp:17422
cached_power get_cached_power_for_binary_exponent(int e)
Definition ollama.hpp:17258
boundaries compute_boundaries(FloatType value)
Definition ollama.hpp:17119
void grisu2(char *buf, int &len, int &decimal_exponent, diyfp m_minus, diyfp v, diyfp m_plus)
Definition ollama.hpp:17758
void grisu2_digit_gen(char *buffer, int &length, int &decimal_exponent, diyfp M_minus, diyfp w, diyfp M_plus)
Definition ollama.hpp:17517
JSON_HEDLEY_RETURNS_NON_NULL char * append_exponent(char *buf, int e)
appends a decimal representation of e to buf
Definition ollama.hpp:17858
detail namespace with internal helper functions
Definition ollama.hpp:272
input_format_t
the supported input formats
Definition ollama.hpp:6199
static void unescape(StringType &s)
string unescaping as described in RFC 6901 (Sect. 4)
Definition ollama.hpp:3028
std::shared_ptr< output_adapter_protocol< CharType > > output_adapter_t
a type to simplify interfaces
Definition ollama.hpp:14982
parse_event_t
Definition ollama.hpp:12226
@ value
the parser finished reading a JSON value
@ key
the parser read a key of a value in an object
@ array_end
the parser read ] and finished processing a JSON array
@ array_start
the parser read [ and started to process a JSON array
@ object_start
the parser read { and started to process a JSON object
@ object_end
the parser read } and finished processing a JSON object
void replace_substring(StringType &s, const StringType &f, const StringType &t)
replace all occurrences of a substring by another string
Definition ollama.hpp:2994
cbor_tag_handler_t
how to treat CBOR tags
Definition ollama.hpp:9208
@ store
store tags as binary type
@ error
throw a parse_error exception in case of a tag
value_t
the JSON type enumeration
Definition ollama.hpp:2896
@ null
null value
@ number_integer
number value (signed integer)
@ boolean
boolean value
@ discarded
discarded by the parser callback function
@ binary
binary array (ordered collection of bytes)
@ object
object (unordered set of name/value pairs)
@ string
string value
@ number_float
number value (floating-point)
@ number_unsigned
number value (unsigned integer)
@ array
array (ordered collection of values)
static bool little_endianness(int num=1) noexcept
determine system byte order
Definition ollama.hpp:9221
std::size_t hash(const BasicJsonType &j)
hash a JSON value
Definition ollama.hpp:6045
bool operator<(const value_t lhs, const value_t rhs) noexcept
comparison operator for JSON types
Definition ollama.hpp:2925
error_handler_t
how to treat decoding errors
Definition ollama.hpp:18075
@ strict
throw a type_error exception in case of invalid UTF-8
@ replace
replace invalid UTF-8 sequences with U+FFFD
StringType escape(StringType s)
string escaping as described in RFC 6901 (Sect. 4)
Definition ollama.hpp:3013
Definition ollama.hpp:34688
namespace for Niels Lohmann
Definition ollama.hpp:5856
static auto to_json(BasicJsonType &j, TargetType &&val) noexcept(noexcept(::nlohmann::to_json(j, std::forward< TargetType >(val)))) -> decltype(::nlohmann::to_json(j, std::forward< TargetType >(val)), void())
convert any value type to a JSON value
Definition ollama.hpp:5880
static auto from_json(BasicJsonType &&j) noexcept(noexcept(::nlohmann::from_json(std::forward< BasicJsonType >(j), detail::identity_tag< TargetType > {}))) -> decltype(::nlohmann::from_json(std::forward< BasicJsonType >(j), detail::identity_tag< TargetType > {}))
convert a JSON value to any value type
Definition ollama.hpp:5870
static auto from_json(BasicJsonType &&j, TargetType &val) noexcept(noexcept(::nlohmann::from_json(std::forward< BasicJsonType >(j), val))) -> decltype(::nlohmann::from_json(std::forward< BasicJsonType >(j), val), void())
convert a JSON value to any value type
Definition ollama.hpp:5860
Definition ollama.hpp:3611
Definition ollama.hpp:3628
Definition ollama.hpp:3683
Definition ollama.hpp:304
Definition ollama.hpp:17106
Definition ollama.hpp:17245
Definition ollama.hpp:16988
static diyfp mul(const diyfp &x, const diyfp &y) noexcept
returns x * y
Definition ollama.hpp:17012
static diyfp normalize_to(const diyfp &x, const int target_exponent) noexcept
normalize x such that the result has the exponent E
Definition ollama.hpp:17094
static diyfp normalize(diyfp x) noexcept
normalize x such that the significand is >= 2^(q-1)
Definition ollama.hpp:17077
static diyfp sub(const diyfp &x, const diyfp &y) noexcept
returns x - y
Definition ollama.hpp:17000
Definition ollama.hpp:5442
Definition ollama.hpp:5122
Definition ollama.hpp:3550
Definition ollama.hpp:3606
Definition ollama.hpp:3575
Definition ollama.hpp:3590
Definition ollama.hpp:4638
Definition ollama.hpp:3146
an iterator value
Definition ollama.hpp:12872
BasicJsonType::array_t::iterator array_iterator
iterator for JSON arrays
Definition ollama.hpp:12876
primitive_iterator_t primitive_iterator
generic iterator for all other types
Definition ollama.hpp:12878
Definition ollama.hpp:3499
Definition ollama.hpp:3486
Definition ollama.hpp:4204
Definition ollama.hpp:4000
Definition ollama.hpp:3864
Definition ollama.hpp:3883
Definition ollama.hpp:3931
Definition ollama.hpp:3954
Definition ollama.hpp:3784
Definition ollama.hpp:3804
Definition ollama.hpp:3841
Definition ollama.hpp:3957
Definition ollama.hpp:3970
Definition ollama.hpp:3777
Definition ollama.hpp:3927
Definition ollama.hpp:3837
Definition ollama.hpp:3848
Definition ollama.hpp:3973
Definition ollama.hpp:3715
Definition ollama.hpp:3696
Definition ollama.hpp:320
Definition ollama.hpp:3558
Definition ollama.hpp:6520
Definition ollama.hpp:3730
Definition ollama.hpp:3979
Definition ollama.hpp:3509
Definition ollama.hpp:4061
Definition ollama.hpp:4057
Definition ollama.hpp:3749
Definition ollama.hpp:9140
Definition ollama.hpp:9109
Definition ollama.hpp:3990
Definition ollama.hpp:4226
Definition ollama.hpp:6507
Definition ollama.hpp:3314
Definition ollama.hpp:3295
Default base class of the basic_json class.
Definition ollama.hpp:13811
Definition ollama.hpp:275
Definition ollama.hpp:3690
Definition ollama.hpp:290
abstract output adapter interface
Definition ollama.hpp:14968
struct to capture the start position of the current token
Definition ollama.hpp:3059
std::size_t chars_read_current_line
the number of characters read in the current line
Definition ollama.hpp:3063
std::size_t lines_read
the number of lines read
Definition ollama.hpp:3065
std::size_t chars_read_total
the total number of characters read
Definition ollama.hpp:3061
Definition ollama.hpp:3229
Definition ollama.hpp:3235
Definition ollama.hpp:5823
Definition ollama.hpp:3166
Definition ollama.hpp:3185
Definition ollama.hpp:4152
Definition ollama.hpp:4106
Definition ollama.hpp:6338
Definition ollama.hpp:26190
Definition ollama.hpp:25304
Definition ollama.hpp:25254
Definition ollama.hpp:25348
Definition ollama.hpp:25400
Definition ollama.hpp:25812
Definition ollama.hpp:25522
Definition ollama.hpp:25129
Definition ollama.hpp:25142
Definition ollama.hpp:13874
SAX interface.
Definition ollama.hpp:6693
virtual bool binary(binary_t &val)=0
a binary value was read
virtual bool number_float(number_float_t val, const string_t &s)=0
a floating-point number was read
virtual bool number_unsigned(number_unsigned_t val)=0
an unsigned integer number was read
virtual bool key(string_t &val)=0
an object key was read
virtual bool string(string_t &val)=0
a string value was read
virtual bool number_integer(number_integer_t val)=0
an integer number was read
virtual bool start_object(std::size_t elements)=0
the beginning of an object was read
virtual bool end_array()=0
the end of an array was read
virtual bool boolean(bool val)=0
a boolean value was read
virtual bool end_object()=0
the end of an object was read
virtual bool null()=0
a null value was read
virtual bool parse_error(std::size_t position, const std::string &last_token, const detail::exception &ex)=0
a parse error occurred
virtual bool start_array(std::size_t elements)=0
the beginning of an array was read
a minimal map-like container that preserves insertion order
Definition ollama.hpp:19057
bool operator()(::nlohmann::detail::value_t lhs, ::nlohmann::detail::value_t rhs) const noexcept
compare two value_t enum values
Definition ollama.hpp:24543